brass-runtime 1.16.0 → 1.17.0

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 (219) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/README.md +287 -23
  3. package/dist/agent/cli/main.cjs +38 -38
  4. package/dist/agent/cli/main.js +6 -6
  5. package/dist/agent/cli/main.mjs +6 -6
  6. package/dist/agent/index.cjs +7 -7
  7. package/dist/agent/index.d.ts +1 -1
  8. package/dist/agent/index.js +6 -6
  9. package/dist/agent/index.mjs +6 -6
  10. package/dist/chunk-2HQTDLHF.mjs +683 -0
  11. package/dist/chunk-36I3M4UC.mjs +370 -0
  12. package/dist/{chunk-QY5FKYEQ.js → chunk-3AYM6WPJ.js} +570 -51
  13. package/dist/chunk-3LOYJFRR.cjs +300 -0
  14. package/dist/chunk-3Y2RIUMM.js +300 -0
  15. package/dist/{chunk-7XOPAB5Q.js → chunk-4P2HHGAX.mjs} +83 -5
  16. package/dist/{chunk-N6VHMOWB.cjs → chunk-4ROBZFL6.cjs} +128 -128
  17. package/dist/{chunk-NC5SDRYE.js → chunk-52OB2ROS.js} +4 -4
  18. package/dist/{chunk-JX3LZQJH.cjs → chunk-52PPNNI4.cjs} +82 -20
  19. package/dist/{chunk-5YOQOXEQ.cjs → chunk-5EC274J5.cjs} +676 -293
  20. package/dist/chunk-5QC7LRZ3.js +229 -0
  21. package/dist/{chunk-7TL2LHQJ.js → chunk-5VRJNBLZ.mjs} +524 -141
  22. package/dist/chunk-62AZW6UT.cjs +313 -0
  23. package/dist/chunk-6IXXWIUM.js +683 -0
  24. package/dist/chunk-6RY2FFN4.mjs +2024 -0
  25. package/dist/chunk-74ZTY6CP.js +2871 -0
  26. package/dist/chunk-7CMJS3QE.mjs +2871 -0
  27. package/dist/{chunk-2WC63LJK.mjs → chunk-7JIJOVCT.js} +20 -10
  28. package/dist/chunk-7X3K5RMS.js +2024 -0
  29. package/dist/chunk-7ZPEZ57L.cjs +2024 -0
  30. package/dist/{chunk-FM4W4QPL.js → chunk-A2OM6NEH.mjs} +5 -4
  31. package/dist/chunk-AGR5B2BC.cjs +683 -0
  32. package/dist/chunk-B33ICAKP.js +313 -0
  33. package/dist/{chunk-J3H54ZRV.mjs → chunk-B5JD23U7.mjs} +1 -1
  34. package/dist/{chunk-F5EUMJL7.mjs → chunk-BKK77SBA.js} +83 -5
  35. package/dist/{chunk-U5KWK3PX.mjs → chunk-C3MDXTRZ.js} +11 -0
  36. package/dist/{chunk-SPUEME2B.cjs → chunk-CZIVE6NT.cjs} +12 -1
  37. package/dist/{chunk-TDVMADDN.js → chunk-DNFJLJMW.mjs} +11 -0
  38. package/dist/{chunk-XDZOO4L5.js → chunk-EJ6BPYVR.mjs} +79 -17
  39. package/dist/chunk-EOC4UHBS.mjs +229 -0
  40. package/dist/chunk-F6XWZQY4.cjs +777 -0
  41. package/dist/{chunk-7LVI2GIN.js → chunk-FH2X7BVP.js} +507 -72
  42. package/dist/{chunk-OOGJ73B6.js → chunk-FHQGHPMO.mjs} +20 -10
  43. package/dist/{chunk-WQ5QNU5R.cjs → chunk-GLE2WY7Z.cjs} +652 -217
  44. package/dist/{chunk-G6IQOE4P.mjs → chunk-GYM3LLGS.mjs} +507 -72
  45. package/dist/{chunk-TVN5I4U6.cjs → chunk-JF5WGYJJ.cjs} +25 -24
  46. package/dist/{chunk-CY33PGEX.mjs → chunk-KH4SYAOS.mjs} +570 -51
  47. package/dist/chunk-KN32XNTH.mjs +313 -0
  48. package/dist/chunk-KQLYONSE.cjs +2871 -0
  49. package/dist/{chunk-7HUOJA4W.cjs → chunk-KZJQ723N.cjs} +90 -80
  50. package/dist/{chunk-CCKHV5BT.mjs → chunk-L2SYFEBS.js} +5 -4
  51. package/dist/{chunk-IJT6RRQ5.cjs → chunk-L6VB5N7Q.cjs} +20 -9
  52. package/dist/{chunk-ZGLD4TVZ.mjs → chunk-MBEJI5HF.mjs} +4 -4
  53. package/dist/{chunk-PRWCB3QL.mjs → chunk-MIIYDLGM.js} +524 -141
  54. package/dist/{chunk-H55LI6WY.js → chunk-MOO4L7F4.mjs} +15 -4
  55. package/dist/chunk-MVGUEJ5Z.cjs +370 -0
  56. package/dist/chunk-PD4EJTQC.cjs +229 -0
  57. package/dist/chunk-PWC3RBQE.mjs +300 -0
  58. package/dist/{chunk-MWXMNYJS.cjs → chunk-Q2I37RP3.cjs} +643 -124
  59. package/dist/{chunk-VFIUZG7J.mjs → chunk-RKGKFN2A.js} +79 -17
  60. package/dist/{chunk-NYL4D7SK.cjs → chunk-SA6HUJVI.cjs} +5 -5
  61. package/dist/chunk-SK7UZRNI.mjs +777 -0
  62. package/dist/{chunk-K2T3DV26.mjs → chunk-TRM4JUZQ.js} +15 -4
  63. package/dist/chunk-UB4B6OFY.js +370 -0
  64. package/dist/{chunk-G3XGCZDQ.js → chunk-UCUBNWM2.js} +1 -1
  65. package/dist/chunk-VWIPB6I5.js +777 -0
  66. package/dist/{chunk-JNFRRJYH.cjs → chunk-WBGRHGBP.cjs} +270 -192
  67. package/dist/{client-CtFmoDvM.d.ts → client-CZHU674n.d.ts} +211 -36
  68. package/dist/core/index.cjs +135 -9
  69. package/dist/core/index.d.ts +238 -33
  70. package/dist/core/index.js +155 -29
  71. package/dist/core/index.mjs +155 -29
  72. package/dist/{effect-CGNl5Rqp.d.ts → effect-DIUHZ9IN.d.ts} +89 -1
  73. package/dist/effectRunner-CFLC32IK.cjs +8 -0
  74. package/dist/{effectRunner-A4CHJXJI.js → effectRunner-L4S7IPT3.js} +2 -2
  75. package/dist/{effectRunner-OPUF6QRN.mjs → effectRunner-NNGG75QA.mjs} +2 -2
  76. package/dist/http/index.cjs +324 -2986
  77. package/dist/http/index.d.ts +54 -68
  78. package/dist/http/index.js +238 -2900
  79. package/dist/http/index.mjs +238 -2900
  80. package/dist/http/testing.cjs +14 -12
  81. package/dist/http/testing.d.ts +5 -4
  82. package/dist/http/testing.js +10 -8
  83. package/dist/http/testing.mjs +10 -8
  84. package/dist/index.cjs +423 -255
  85. package/dist/index.d.ts +87 -69
  86. package/dist/index.js +301 -133
  87. package/dist/index.mjs +301 -133
  88. package/dist/observability/index.cjs +18 -531
  89. package/dist/observability/index.d.ts +81 -8
  90. package/dist/observability/index.js +25 -538
  91. package/dist/observability/index.mjs +25 -538
  92. package/dist/perf/cli.cjs +401 -0
  93. package/dist/perf/cli.d.ts +1 -0
  94. package/dist/perf/cli.js +401 -0
  95. package/dist/perf/cli.mjs +401 -0
  96. package/dist/perf/index.cjs +141 -0
  97. package/dist/perf/index.d.ts +483 -0
  98. package/dist/perf/index.js +141 -0
  99. package/dist/perf/index.mjs +141 -0
  100. package/dist/schedule-CK3Ml_7p.d.ts +259 -0
  101. package/dist/schema/index.cjs +6 -2
  102. package/dist/schema/index.d.ts +3 -1
  103. package/dist/schema/index.js +5 -1
  104. package/dist/schema/index.mjs +5 -1
  105. package/dist/{server-C8hDXA74.d.ts → server-D6JZ15_e.d.ts} +16 -4
  106. package/dist/{stream-dvSs0QS5.d.ts → stream-B4oK9JFP.d.ts} +1 -1
  107. package/dist/{tracer-B5tRH9H7.d.ts → tracer-Hwt1cl7h.d.ts} +13 -54
  108. package/dist/{tracing-Dt9S_6V8.d.ts → tracing-DqbTKGcf.d.ts} +1 -1
  109. package/docs/ARCHITECTURE.md +292 -0
  110. package/docs/README.md +65 -0
  111. package/docs/adr/0001-ai-context-pack.md +32 -0
  112. package/docs/agent-apply-mode.md +104 -0
  113. package/docs/agent-approvals.md +110 -0
  114. package/docs/agent-batch.md +185 -0
  115. package/docs/agent-boundaries.md +112 -0
  116. package/docs/agent-chat-sessions.md +160 -0
  117. package/docs/agent-ci.md +17 -0
  118. package/docs/agent-cli.md +405 -0
  119. package/docs/agent-config.md +480 -0
  120. package/docs/agent-context-discovery.md +159 -0
  121. package/docs/agent-copilot-like-dx.md +126 -0
  122. package/docs/agent-declarative-optimized-planning.md +138 -0
  123. package/docs/agent-dx.md +224 -0
  124. package/docs/agent-env-files.md +126 -0
  125. package/docs/agent-follow-up-context.md +43 -0
  126. package/docs/agent-global-usage.md +180 -0
  127. package/docs/agent-init.md +109 -0
  128. package/docs/agent-install-and-configure.md +516 -0
  129. package/docs/agent-language-workspace-ux.md +99 -0
  130. package/docs/agent-llm-adapters.md +123 -0
  131. package/docs/agent-local-install.md +190 -0
  132. package/docs/agent-local-tests.md +51 -0
  133. package/docs/agent-observability.md +155 -0
  134. package/docs/agent-patch-quality-loop.md +162 -0
  135. package/docs/agent-presets.md +22 -0
  136. package/docs/agent-project-commands.md +237 -0
  137. package/docs/agent-project-intelligence.md +156 -0
  138. package/docs/agent-redaction.md +18 -0
  139. package/docs/agent-release-readiness.md +76 -0
  140. package/docs/agent-rollback-safety.md +162 -0
  141. package/docs/agent-rollback.md +23 -0
  142. package/docs/agent-run-artifacts.md +16 -0
  143. package/docs/agent-vscode-auto-discovery.md +137 -0
  144. package/docs/agent-vscode-batch-runner.md +100 -0
  145. package/docs/agent-vscode-chat-layout.md +90 -0
  146. package/docs/agent-vscode-clean-install.md +147 -0
  147. package/docs/agent-vscode-code-actions.md +70 -0
  148. package/docs/agent-vscode-diff-preview.md +45 -0
  149. package/docs/agent-vscode-inline-assist.md +56 -0
  150. package/docs/agent-vscode-install.md +186 -0
  151. package/docs/agent-vscode-model-setup.md +97 -0
  152. package/docs/agent-vscode-patch-preview.md +92 -0
  153. package/docs/agent-vscode-problems.md +79 -0
  154. package/docs/agent-vscode-project-dashboard.md +106 -0
  155. package/docs/agent-vscode-run-history.md +92 -0
  156. package/docs/agent-vscode-ux.md +73 -0
  157. package/docs/ai/INVARIANTS.md +84 -0
  158. package/docs/ai/PROJECT_MAP.md +338 -0
  159. package/docs/ai/PUBLIC_API.md +339 -0
  160. package/docs/ai/VALIDATION_MATRIX.md +67 -0
  161. package/docs/api-polish.md +37 -0
  162. package/docs/cancellation.md +162 -0
  163. package/docs/coverage.md +46 -0
  164. package/docs/framework-integrations.md +38 -0
  165. package/docs/frameworks/angular.md +153 -0
  166. package/docs/frameworks/express.md +125 -0
  167. package/docs/frameworks/fastify.md +124 -0
  168. package/docs/frameworks/nestjs.md +282 -0
  169. package/docs/frameworks/nextjs.md +147 -0
  170. package/docs/frameworks/react.md +139 -0
  171. package/docs/frameworks/vanilla.md +224 -0
  172. package/docs/getting-started.md +159 -0
  173. package/docs/guides/README.md +40 -0
  174. package/docs/guides/circuit-breaker.md +89 -0
  175. package/docs/guides/error-handling.md +91 -0
  176. package/docs/guides/getting-started.md +107 -0
  177. package/docs/guides/layers.md +189 -0
  178. package/docs/guides/metrics.md +101 -0
  179. package/docs/guides/resource-management.md +141 -0
  180. package/docs/guides/retry.md +215 -0
  181. package/docs/guides/semaphore.md +66 -0
  182. package/docs/guides/streams.md +117 -0
  183. package/docs/guides/supervisors.md +98 -0
  184. package/docs/guides/testing.md +162 -0
  185. package/docs/guides/tracing.md +71 -0
  186. package/docs/http-recipes.md +399 -0
  187. package/docs/http.md +749 -0
  188. package/docs/modules.md +285 -0
  189. package/docs/nestjs.md +6 -0
  190. package/docs/observability-collector-smoke.md +31 -0
  191. package/docs/observability-framework-examples.md +110 -0
  192. package/docs/observability.md +649 -0
  193. package/docs/otel-collector-smoke.yaml +27 -0
  194. package/docs/performance-profiler.md +199 -0
  195. package/docs/production-readiness.md +73 -0
  196. package/docs/recipes/README.md +12 -0
  197. package/docs/recipes/http-server.md +45 -0
  198. package/docs/recipes/layers.md +44 -0
  199. package/docs/recipes/performance.md +47 -0
  200. package/docs/recipes/runtime.md +41 -0
  201. package/docs/recipes/testing.md +41 -0
  202. package/docs/release.md +53 -0
  203. package/docs/wasm-bounded-queues.md +44 -0
  204. package/docs/wasm-engine-observability-benchmarks.md +85 -0
  205. package/docs/wasm-fiber-engine.md +117 -0
  206. package/docs/wasm-scheduler-state-machine.md +122 -0
  207. package/docs/wasm-stream-chunks.md +54 -0
  208. package/package.json +22 -2
  209. package/dist/chunk-45F7OKGT.cjs +0 -104
  210. package/dist/chunk-7V4KY4RL.mjs +0 -104
  211. package/dist/chunk-DJQ7OMMB.cjs +0 -144
  212. package/dist/chunk-GOV47PPB.mjs +0 -552
  213. package/dist/chunk-JF4XXPZ5.cjs +0 -552
  214. package/dist/chunk-KCPT2D6G.js +0 -552
  215. package/dist/chunk-NOYZIMUJ.mjs +0 -144
  216. package/dist/chunk-PNVFW245.js +0 -144
  217. package/dist/chunk-ROJC3NBJ.js +0 -104
  218. package/dist/effectRunner-3ZHAD3LE.cjs +0 -8
  219. package/dist/schedule-Fque9Abz.d.ts +0 -70
@@ -0,0 +1,199 @@
1
+ # Brass Performance Profiler
2
+
3
+ `brass-runtime/perf` is the built-in profiling surface for runtime and HTTP
4
+ performance work. It is intentionally dependency-free and runs against a local
5
+ Node HTTP server so it can be used in CI, during local optimization, and before
6
+ changing runtime internals.
7
+
8
+ ## Run it
9
+
10
+ ```bash
11
+ npm run perf
12
+ npm run perf:json
13
+ npm run benchmark:perf
14
+ npm run perf:runtime:ab
15
+ npm run perf:runtime:soak
16
+ npm run perf:runtime:budget
17
+ npm run perf:http:memory
18
+ npm run perf:history
19
+ ```
20
+
21
+ For memory-sensitive runs, expose GC:
22
+
23
+ ```bash
24
+ node --expose-gc --import tsx src/perf/cli.ts --force-gc
25
+ node --expose-gc --import tsx src/perf/cli.ts --profile http-memory --calls 100000 --concurrency 512 --delay-ms 2 --force-gc
26
+ ```
27
+
28
+ Focused examples:
29
+
30
+ ```bash
31
+ npm run perf -- --profile runtime --runtime-iterations 10000
32
+ npm run perf -- --profile runtime-ab --baseline fiber-only --candidate default
33
+ npm run perf -- --profile runtime-soak --rounds 10 --runtime-iterations 100000
34
+ npm run perf -- --profile http --calls 20000 --concurrency 512 --delay-ms 2 --force-gc
35
+ npm run perf -- --profile http --variants default-json,default-json-observed --json
36
+ npm run perf -- --profile http-memory --calls 20000 --concurrency 512 --rounds 2 --force-gc
37
+ npm run perf -- --profile runtime-ab --record-history --save-baseline runtime-main
38
+ npm run perf -- --profile runtime-ab --compare-baseline runtime-main --fail-on-baseline-regression
39
+ ```
40
+
41
+ Environment variables mirror the CLI flags:
42
+
43
+ - `BRASS_PERF_PROFILE=all|runtime|http`
44
+ - `BRASS_PERF_CALLS`
45
+ - `BRASS_PERF_CONCURRENCY`
46
+ - `BRASS_PERF_DELAY_MS`
47
+ - `BRASS_PERF_WARMUP_CALLS`
48
+ - `BRASS_PERF_VARIANTS`
49
+ - `BRASS_PERF_RUNTIME_ITERATIONS`
50
+ - `BRASS_PERF_RUNTIME_CHAIN_DEPTH`
51
+ - `BRASS_PERF_RUNTIME_VARIANT`
52
+ - `BRASS_PERF_BASELINE`
53
+ - `BRASS_PERF_CANDIDATE`
54
+ - `BRASS_PERF_ROUNDS`
55
+ - `BRASS_PERF_FORCE_GC=true`
56
+ - `BRASS_PERF_JSON=true`
57
+ - `BRASS_PERF_RECORD_HISTORY=true`
58
+ - `BRASS_PERF_HISTORY_DIR`
59
+ - `BRASS_PERF_SAVE_BASELINE`
60
+ - `BRASS_PERF_COMPARE_BASELINE`
61
+ - `BRASS_PERF_FAIL_ON_BASELINE_REGRESSION=true`
62
+
63
+ ## Import it
64
+
65
+ ```ts
66
+ import {
67
+ comparePerfToBaseline,
68
+ formatPerformanceReport,
69
+ loadPerfBaseline,
70
+ profileHttpLayers,
71
+ profileRuntimePrimitives,
72
+ runBrassPerformanceProfile,
73
+ savePerfBaseline,
74
+ createPerfHistoryEntry,
75
+ } from "brass-runtime/perf";
76
+
77
+ const report = await runBrassPerformanceProfile({
78
+ http: {
79
+ calls: 20_000,
80
+ concurrency: 512,
81
+ delayMs: 2,
82
+ forceGc: true,
83
+ variants: ["default-json", "default-json-observed"],
84
+ },
85
+ });
86
+
87
+ console.log(formatPerformanceReport(report));
88
+
89
+ const entry = createPerfHistoryEntry("all", report);
90
+ await savePerfBaseline("daily-main", entry);
91
+ const baseline = await loadPerfBaseline("daily-main");
92
+ if (baseline) {
93
+ console.log(comparePerfToBaseline(entry, baseline));
94
+ }
95
+ ```
96
+
97
+ ## What it measures
98
+
99
+ Runtime profile:
100
+
101
+ - top-level `asyncSucceed`
102
+ - top-level `asyncFail`
103
+ - top-level `asyncSync`
104
+ - deep `flatMap` chains
105
+ - `FiberRef` update/get chains
106
+ - fibers started per primitive
107
+ - ns/op and operations per second
108
+
109
+ Runtime A/B profile:
110
+
111
+ - `fiber-only` baseline for forced fiber execution
112
+ - `default` candidate with native top-level fast path for no-hooks/no-lane
113
+ `Succeed`, `Fail`, `Sync`, synchronous continuations, `FiberRef` locals, and
114
+ synchronous/asynchronous callback effects
115
+ - `active-hooks` to measure EventBus overhead
116
+ - `recorder` to measure bounded flight recorder overhead
117
+ - `wide-scheduler` to measure larger single-lane queue settings
118
+
119
+ Runtime soak profile:
120
+
121
+ - repeated runtime-only rounds
122
+ - throughput trend from first to last round
123
+ - heap/rss trend across rounds
124
+ - hottest primitive per round
125
+
126
+ HTTP layer profile:
127
+
128
+ - `node-http-text`
129
+ - `wire-raw`
130
+ - `default-minimal-json`
131
+ - `default-balanced-no-adaptive-json`
132
+ - `default-balanced-json`
133
+ - `default-json`
134
+ - `default-json-observed`
135
+
136
+ Each HTTP variant reports throughput, latency percentiles, client/server
137
+ in-flight peaks, queue depth, adaptive limiter state when present, span
138
+ retention when observability is enabled, and memory deltas.
139
+
140
+ HTTP long-run memory lab:
141
+
142
+ - defaults to `forceGc: true`, so use `node --expose-gc` for the strongest
143
+ retained-memory signal
144
+ - compares node transport, wire raw, minimal, balanced without adaptive,
145
+ balanced, default, and default+observability variants
146
+ - reports heap/rss totals, max p99, mean throughput, errors, and
147
+ `heapDeltaPer10kRequestsMb`
148
+ - highlights whether memory is `ok`, `watch`, `critical`, or `unknown-gc`
149
+ - compares default+observability against default for heap/10k and throughput
150
+
151
+ Memory profile:
152
+
153
+ - before/after snapshots
154
+ - heap/rss/external/array-buffer deltas
155
+ - GC availability
156
+ - optional forced GC via `--force-gc`
157
+
158
+ ## History and baselines
159
+
160
+ Perf history is local and dependency-free:
161
+
162
+ - history appends compact JSONL entries to `.brass/perf-history/runs.jsonl`
163
+ - baselines are stored under `.brass/perf-history/baselines/*.json`
164
+ - entries keep normalized metrics rather than full reports by default
165
+ - `--record-history` writes the current run
166
+ - `--save-baseline NAME` stores the current run as a named baseline
167
+ - `--compare-baseline NAME` compares matching metrics by name/tags
168
+ - `--fail-on-baseline-regression` turns a failed baseline comparison into a
169
+ non-zero CLI exit code
170
+
171
+ Thresholds are intentionally simple:
172
+
173
+ - throughput and ops/s are higher-is-better
174
+ - latency, heap/rss, ns/op, and errors are lower-is-better
175
+ - `--baseline-max-regression-percent` defaults to `10`
176
+ - `--baseline-max-heap-regression-percent` defaults to `25`
177
+ - `--baseline-warn-at-ratio` defaults to `0.5`
178
+
179
+ ## Recommendations
180
+
181
+ `recommendPerformance` turns raw numbers into actionable warnings:
182
+
183
+ - default client throughput compared to `node:http`
184
+ - observability overhead compared to unobserved default client
185
+ - retained heap per HTTP variant and full profile
186
+ - queueing and adaptive limiter pressure
187
+ - high HTTP p99 latency
188
+ - runtime primitives below local thresholds
189
+
190
+ These recommendations are heuristics, not release gates. Use the focused
191
+ benchmark budgets for stable regression checks:
192
+
193
+ ```bash
194
+ npm run perf:runtime:budget
195
+ npm run perf:http:memory
196
+ npm run benchmark:runtime:budget
197
+ npm run benchmark:http:budget
198
+ npm run benchmark:observability:budget
199
+ ```
@@ -0,0 +1,73 @@
1
+ # Production Readiness
2
+
3
+ This checklist is the release gate for using `brass-runtime` in production-like
4
+ services.
5
+
6
+ ## HTTP Defaults
7
+
8
+ Use `makeDefaultHttpClient` for application clients. The `default` preset enables
9
+ timeout, deduplication, priority scheduling, retry, conservative adaptive
10
+ concurrency, safe-method cache, compression, stats, cache controls, and
11
+ `cancelAll`.
12
+
13
+ The adaptive limiter is intentionally conservative in presets:
14
+
15
+ - `minSamples` prevents cold-start latency from changing limits too early.
16
+ - `decreaseThreshold` creates a deadband for normal latency jitter.
17
+ - `maxDecreaseRatio` caps one-step decreases so a noisy sample cannot collapse
18
+ concurrency.
19
+ - Presets avoid `minLimit: 1`; use that only when a caller explicitly wants a
20
+ nearly-closed circuit under pressure.
21
+
22
+ When debugging throughput, compare requested concurrency with
23
+ `serverMaxInFlight`, `adaptiveFinalLimit`, and `adaptiveMaxQueueDepth` before
24
+ assuming a memory leak.
25
+
26
+ ## Validation
27
+
28
+ Baseline gate:
29
+
30
+ ```bash
31
+ npm run test:types
32
+ npm test
33
+ ```
34
+
35
+ Public package gate:
36
+
37
+ ```bash
38
+ npm run build
39
+ npm run validate:cjs
40
+ ```
41
+
42
+ Benchmark gates:
43
+
44
+ ```bash
45
+ npm run benchmark:observability:budget
46
+ npm run benchmark:http:budget
47
+ npm run benchmark:adaptive
48
+ ```
49
+
50
+ Soak gate:
51
+
52
+ ```bash
53
+ npm run benchmark:http:soak
54
+ npm run benchmark:adaptive:soak
55
+ BRASS_HTTP_BENCH_CALLS=100000 node --expose-gc --import tsx src/benchmarks/runner.ts http-concurrent
56
+ ```
57
+
58
+ Treat sustained positive `heapDeltaMb` after explicit GC as leak evidence. Treat
59
+ RSS-only growth as a signal to investigate, not proof of a leak.
60
+
61
+ ## Operational Notes
62
+
63
+ - Attach HTTP observability with `middleware: [withHttpObservability(obs)]`.
64
+ - HTTP observability records adaptive limiter gauges when the wrapped client
65
+ owns a limiter; keep the optional limiter key label disabled unless keys are
66
+ low-cardinality.
67
+ - Always call `observability.shutdown()` during service shutdown.
68
+ - Call HTTP `shutdown()` as part of graceful shutdown when using default or
69
+ adaptive-limiter clients so queue/TTL timers and waiters are cleaned up.
70
+ - Keep exporter queues bounded and use `flush()` before process exit.
71
+ - Prefer local benchmark servers over public demo APIs for repeatable numbers.
72
+ - Keep benchmark budgets advisory in developer machines and mandatory in CI once
73
+ the CI hardware profile is stable.
@@ -0,0 +1,12 @@
1
+ # Brass Recipes
2
+
3
+ Copyable happy paths for the first release.
4
+
5
+ - [Runtime](./runtime.md)
6
+ - [Layers](./layers.md)
7
+ - [HTTP server](./http-server.md)
8
+ - [Testing](./testing.md)
9
+ - [Performance](./performance.md)
10
+
11
+ These recipes use the public exports a new user should reach for first. Deeper
12
+ guides still live under `docs/guides/`.
@@ -0,0 +1,45 @@
1
+ # HTTP Server Recipe
2
+
3
+ Use `HttpServer` for the discoverable happy path: define routes, build a
4
+ router, and manage the Node listener as a resource.
5
+
6
+ ```ts
7
+ import { asyncSucceed, asyncSync, runPromise, useResource } from "brass-runtime";
8
+ import { HttpServer, s } from "brass-runtime/http";
9
+
10
+ const User = s.object({
11
+ id: s.nonEmptyString(),
12
+ name: s.nonEmptyString(),
13
+ });
14
+
15
+ const routes = [
16
+ HttpServer.route("GET", "/users/:id", {
17
+ params: s.object({ id: s.nonEmptyString() }),
18
+ response: User,
19
+ }, (ctx) =>
20
+ asyncSucceed(HttpServer.json({
21
+ id: ctx.params.id,
22
+ name: "Ada",
23
+ })),
24
+ ),
25
+ HttpServer.healthRoute(),
26
+ HttpServer.readinessRoute(),
27
+ ];
28
+
29
+ const router = HttpServer.router(routes, {
30
+ middleware: [HttpServer.middleware.header("x-powered-by", "brass-runtime")],
31
+ });
32
+
33
+ await runPromise(
34
+ useResource(
35
+ router.listen({ port: 3000 }),
36
+ (server) => asyncSync(() => {
37
+ console.log(server.url());
38
+ }),
39
+ ),
40
+ );
41
+ ```
42
+
43
+ Validation failures are returned as JSON responses. Handler failures are mapped
44
+ to server error responses by the router, while listener failures use typed
45
+ `NodeHttpServerError` values.
@@ -0,0 +1,44 @@
1
+ # Layers Recipe
2
+
3
+ Use `defineService` for typed service tags, `Layer.effect` or `Layer.value` to
4
+ provide them, and `provideContext` to run a program with a scoped dependency
5
+ graph.
6
+
7
+ ```ts
8
+ import {
9
+ Layer,
10
+ LayerContext,
11
+ asyncSucceed,
12
+ defineService,
13
+ provideContext,
14
+ runPromise,
15
+ } from "brass-runtime";
16
+
17
+ type Config = { readonly baseUrl: string };
18
+ type Repo = { readonly findUser: (id: string) => string };
19
+
20
+ const Config = defineService<Config>("Config");
21
+ const Repo = defineService<Repo>("Repo");
22
+
23
+ const ConfigLayer = Layer.value(Config, { baseUrl: "https://api.example.com" });
24
+
25
+ const RepoLayer = Layer.effect(Repo, (ctx: LayerContext) => {
26
+ const config = ctx.unsafeGet(Config);
27
+ return asyncSucceed({
28
+ findUser: (id) => `${config.baseUrl}/users/${id}`,
29
+ });
30
+ });
31
+
32
+ const AppLayer = Layer.compose(ConfigLayer, RepoLayer);
33
+
34
+ const userUrl = await runPromise(
35
+ provideContext(AppLayer, (ctx) =>
36
+ asyncSucceed(ctx.unsafeGet(Repo).findUser("u1")),
37
+ ),
38
+ );
39
+
40
+ console.log(userUrl);
41
+ ```
42
+
43
+ Missing services throw `MissingLayerServiceError`; use `formatLayerError` when
44
+ surfacing the message.
@@ -0,0 +1,47 @@
1
+ # Performance Recipe
2
+
3
+ Use the profiler before and after runtime, HTTP, scheduler, layer, schedule, or
4
+ observability changes.
5
+
6
+ ```bash
7
+ npm run perf -- --profile runtime-ab
8
+ npm run perf -- --profile runtime-soak
9
+ npm run perf:http:memory -- --calls 1000 --concurrency 64 --variants default-json,default-json-observed
10
+ ```
11
+
12
+ Save a local baseline when the machine is stable:
13
+
14
+ ```bash
15
+ npm run perf -- --profile runtime-ab --record-history --save-baseline runtime-main
16
+ npm run perf -- --profile runtime-ab --compare-baseline runtime-main --fail-on-baseline-regression
17
+ ```
18
+
19
+ For memory-sensitive HTTP work, expose GC:
20
+
21
+ ```bash
22
+ node --expose-gc --import tsx src/perf/cli.ts --profile http-memory --calls 100000 --concurrency 512 --delay-ms 2 --force-gc
23
+ ```
24
+
25
+ Programmatic API:
26
+
27
+ ```ts
28
+ import {
29
+ comparePerfToBaseline,
30
+ createPerfHistoryEntry,
31
+ loadPerfBaseline,
32
+ runBrassPerformanceProfile,
33
+ savePerfBaseline,
34
+ } from "brass-runtime/perf";
35
+
36
+ const report = await runBrassPerformanceProfile({ http: false });
37
+ const entry = createPerfHistoryEntry("runtime", report);
38
+ await savePerfBaseline("runtime-main", entry);
39
+
40
+ const baseline = await loadPerfBaseline("runtime-main");
41
+ if (baseline) {
42
+ console.log(comparePerfToBaseline(entry, baseline));
43
+ }
44
+ ```
45
+
46
+ Treat non-GC heap deltas as allocator churn until a GC-aware run confirms
47
+ retained memory.
@@ -0,0 +1,41 @@
1
+ # Runtime Recipe
2
+
3
+ Use `runPromise` for the short path and `runExit` when you want the complete
4
+ `Exit`/`Cause` value.
5
+
6
+ ```ts
7
+ import { asyncFlatMap, asyncSucceed, runExit, runPromise } from "brass-runtime";
8
+
9
+ const program = asyncFlatMap(asyncSucceed(41), (n) => asyncSucceed(n + 1));
10
+
11
+ const value = await runPromise(program);
12
+ const exit = await runExit(program);
13
+
14
+ console.log(value); // 42
15
+ console.log(exit);
16
+ ```
17
+
18
+ Use `makeRuntime` when the app owns runtime configuration.
19
+
20
+ ```ts
21
+ import { makeRuntime, asyncSync } from "brass-runtime";
22
+
23
+ const runtime = makeRuntime({ config: { port: 3000 } }, { inferLane: false });
24
+
25
+ const port = await runtime.toPromise(
26
+ asyncSync((env: { config: { port: number } }) => env.config.port),
27
+ );
28
+ ```
29
+
30
+ If you care about typed failures, prefer `runExit` at the boundary and format
31
+ the cause in logs or HTTP responses.
32
+
33
+ ```ts
34
+ import { Cause, asyncFail, runExit } from "brass-runtime";
35
+
36
+ const exit = await runExit(asyncFail({ _tag: "NotFound", id: "u1" }));
37
+
38
+ if (exit._tag === "Failure") {
39
+ console.error(Cause.pretty(exit.cause));
40
+ }
41
+ ```
@@ -0,0 +1,41 @@
1
+ # Testing Recipe
2
+
3
+ Use `makeTestRuntime` for deterministic clocks and scheduler control.
4
+
5
+ ```ts
6
+ import { asyncFlatMap, asyncSucceed, sleep, timeout } from "brass-runtime";
7
+ import { makeTestRuntime } from "brass-runtime";
8
+
9
+ const test = makeTestRuntime();
10
+
11
+ const program = asyncFlatMap(sleep(1000), () => asyncSucceed("done"));
12
+
13
+ const result = test.run(program);
14
+ await test.advance(1000);
15
+
16
+ console.log(await result); // done
17
+ ```
18
+
19
+ Use HTTP testing helpers for client code without touching the network.
20
+
21
+ ```ts
22
+ import {
23
+ makeJsonHttpResponse,
24
+ makeMockHttpClient,
25
+ runHttpEffect,
26
+ } from "brass-runtime/http/testing";
27
+
28
+ const client = makeMockHttpClient((req) =>
29
+ makeJsonHttpResponse({ ok: true, url: req.url }),
30
+ );
31
+
32
+ const response = await runHttpEffect(client({ method: "GET", url: "/health" }));
33
+ console.log(response.status);
34
+ ```
35
+
36
+ For typed failures, assert on `Exit` instead of catching thrown values.
37
+
38
+ ```ts
39
+ const exit = await test.runExit(timeout(asyncSucceed("ok"), 1));
40
+ console.log(exit._tag);
41
+ ```
@@ -0,0 +1,53 @@
1
+ # First Release Checklist
2
+
3
+ This is the release gate for the first public `brass-runtime` release.
4
+
5
+ ## Release command
6
+
7
+ ```bash
8
+ npm run release:check
9
+ ```
10
+
11
+ `release:check` covers:
12
+
13
+ - TypeScript API/type checks.
14
+ - Full Vitest suite.
15
+ - TS bundle build.
16
+ - CJS compatibility validation.
17
+ - Runtime profiler budget.
18
+ - Runtime benchmark budget.
19
+ - HTTP benchmark budget.
20
+ - Observability benchmark budget.
21
+
22
+ ## Manual release notes
23
+
24
+ Before publishing:
25
+
26
+ - Review `README.md` and `docs/recipes/`.
27
+ - Run a GC-aware HTTP memory lab on the release machine:
28
+
29
+ ```bash
30
+ node --expose-gc --import tsx src/perf/cli.ts --profile http-memory --calls 100000 --concurrency 512 --delay-ms 2 --force-gc
31
+ ```
32
+
33
+ - Save a local perf baseline:
34
+
35
+ ```bash
36
+ npm run perf -- --profile runtime-ab --record-history --save-baseline first-release-runtime
37
+ npm run perf -- --profile http-memory --calls 20000 --concurrency 512 --record-history --save-baseline first-release-http-memory
38
+ ```
39
+
40
+ - Confirm `npm pack --dry-run` includes only package files expected by
41
+ `package.json`.
42
+
43
+ ## First-release scope
44
+
45
+ - Core runtime, fibers, scopes, `Cause`, interruptibility, `FiberRef`.
46
+ - Layer 2.0 and Schedule 2.0.
47
+ - Streams and pipelines.
48
+ - HTTP client/server, schema validation, lifecycle middleware.
49
+ - Observability and runtime health/readiness.
50
+ - Performance profiler, budgets, history, and baselines.
51
+ - Brass Agent CLI/library surface.
52
+
53
+ Do not publish `.brass/perf-history`; it is intentionally local evidence.
@@ -0,0 +1,44 @@
1
+ # WASM bounded queues / ring buffers
2
+
3
+ `brass-runtime` now has an engine-selectable bounded ring buffer abstraction.
4
+
5
+ The public queue API remains backward compatible:
6
+
7
+ ```ts
8
+ bounded<number>(1024, "backpressure");
9
+ ```
10
+
11
+ You can force the ring storage engine when benchmarking:
12
+
13
+ ```ts
14
+ bounded<number>(1024, "backpressure", { engine: "wasm" });
15
+ bounded<number>(1024, "sliding", { engine: "wasm" });
16
+ bounded<number>(1024, "dropping", { engine: "wasm" });
17
+ ```
18
+
19
+ Or use the lower-level ring buffer factory:
20
+
21
+ ```ts
22
+ import { makeBoundedRingBuffer } from "brass-runtime";
23
+
24
+ const ring = makeBoundedRingBuffer<number>(1024, 1024, { engine: "wasm" });
25
+ ring.push(1);
26
+ ring.shift();
27
+ ```
28
+
29
+ ## Engine semantics
30
+
31
+ - `engine: "js"`: always uses the TypeScript `RingBuffer`.
32
+ - `engine: "wasm"`: requires `wasm/pkg` to expose `BrassWasmRingBuffer`; throws if the WASM package was not rebuilt.
33
+ - `engine: "auto"`: uses WASM when available, otherwise falls back to the JS ring buffer.
34
+
35
+ ## Performance note
36
+
37
+ This is intentionally selective. WASM helps most when the queue is hot, bounded, and dominated by ring-buffer state management. If every operation crosses the JS/WASM boundary with large object payloads, JS can still win. Benchmark both modes before making WASM the default in production.
38
+
39
+ After changing Rust, rebuild the package:
40
+
41
+ ```bash
42
+ npm run build:wasm
43
+ npm run build
44
+ ```
@@ -0,0 +1,85 @@
1
+ # WASM engine observability and benchmarks
2
+
3
+ This layer makes `auto` observable instead of implicit.
4
+
5
+ ```ts
6
+ type EngineStats<T> = {
7
+ engine: "js" | "wasm";
8
+ data: T;
9
+ fallbackUsed: boolean;
10
+ };
11
+ ```
12
+
13
+ ## Capability detection
14
+
15
+ ```ts
16
+ import { runtimeCapabilities } from "brass-runtime";
17
+
18
+ console.log(runtimeCapabilities());
19
+ ```
20
+
21
+ Returns:
22
+
23
+ ```ts
24
+ {
25
+ wasmAvailable: boolean;
26
+ wasmFiberEngine: boolean;
27
+ wasmRingBuffer: boolean;
28
+ wasmScheduler: boolean;
29
+ wasmFiberRegistry: boolean;
30
+ wasmStreamChunks: boolean;
31
+ }
32
+ ```
33
+
34
+ ## Runtime stats
35
+
36
+ ```ts
37
+ const runtime = Runtime.makeWithEngine({}, "auto");
38
+ console.log(runtime.capabilities());
39
+ console.log(runtime.stats());
40
+ ```
41
+
42
+ `runtime.stats()` now returns `EngineStats<FiberEngineStats>`.
43
+
44
+ ## Scheduler stats
45
+
46
+ ```ts
47
+ const scheduler = new Scheduler({ engine: "auto" });
48
+ console.log(scheduler.stats());
49
+ ```
50
+
51
+ `fallbackUsed: true` means `auto` selected JS because the corresponding WASM capability was not available.
52
+
53
+ ## Ring buffer stats
54
+
55
+ ```ts
56
+ const q = makeBoundedRingBuffer<number>(1024, 1024, { engine: "auto" });
57
+ q.push(1);
58
+ q.shift();
59
+ console.log(q.stats());
60
+ ```
61
+
62
+ ## Stream chunk stats
63
+
64
+ ```ts
65
+ const chunker = makeStreamChunker<number>(256, { engine: "auto" });
66
+ console.log(chunker.stats());
67
+ ```
68
+
69
+ ## Benchmarks
70
+
71
+ Run:
72
+
73
+ ```bash
74
+ npm run build:wasm
75
+ npm run benchmark wasm-engines
76
+ ```
77
+
78
+ JSON output:
79
+
80
+ ```bash
81
+ npm run build:wasm
82
+ npm run benchmark:json wasm-engines
83
+ ```
84
+
85
+ The benchmark report includes the runtime capability snapshot, so results can be compared against whether WASM was actually available.