@vessel-dsp/compiler 0.0.0-stage → 0.2.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 (226) hide show
  1. package/README.md +314 -2
  2. package/dist/bake.d.ts +38 -0
  3. package/dist/bake.d.ts.map +1 -0
  4. package/dist/bake.js +101 -0
  5. package/dist/bake.js.map +1 -0
  6. package/dist/bbd-clock.d.ts +171 -0
  7. package/dist/bbd-clock.d.ts.map +1 -0
  8. package/dist/bbd-clock.js +1750 -0
  9. package/dist/bbd-clock.js.map +1 -0
  10. package/dist/block-row.d.ts +51 -0
  11. package/dist/block-row.d.ts.map +1 -0
  12. package/dist/block-row.js +17 -0
  13. package/dist/block-row.js.map +1 -0
  14. package/dist/bypass.d.ts +3 -0
  15. package/dist/bypass.d.ts.map +1 -0
  16. package/dist/bypass.js +228 -0
  17. package/dist/bypass.js.map +1 -0
  18. package/dist/compile.d.ts +24 -0
  19. package/dist/compile.d.ts.map +1 -0
  20. package/dist/compile.js +344 -0
  21. package/dist/compile.js.map +1 -0
  22. package/dist/converter-scale.d.ts +14 -0
  23. package/dist/converter-scale.d.ts.map +1 -0
  24. package/dist/converter-scale.js +133 -0
  25. package/dist/converter-scale.js.map +1 -0
  26. package/dist/couple.d.ts +28 -0
  27. package/dist/couple.d.ts.map +1 -0
  28. package/dist/couple.js +567 -0
  29. package/dist/couple.js.map +1 -0
  30. package/dist/dangling-active-terminal.d.ts +47 -0
  31. package/dist/dangling-active-terminal.d.ts.map +1 -0
  32. package/dist/dangling-active-terminal.js +542 -0
  33. package/dist/dangling-active-terminal.js.map +1 -0
  34. package/dist/declared-program.d.ts +23 -0
  35. package/dist/declared-program.d.ts.map +1 -0
  36. package/dist/declared-program.js +387 -0
  37. package/dist/declared-program.js.map +1 -0
  38. package/dist/denomination.d.ts +48 -0
  39. package/dist/denomination.d.ts.map +1 -0
  40. package/dist/denomination.js +27 -0
  41. package/dist/denomination.js.map +1 -0
  42. package/dist/device-laws.d.ts +237 -0
  43. package/dist/device-laws.d.ts.map +1 -0
  44. package/dist/device-laws.js +3497 -0
  45. package/dist/device-laws.js.map +1 -0
  46. package/dist/diagnostics.d.ts +13 -0
  47. package/dist/diagnostics.d.ts.map +1 -0
  48. package/dist/diagnostics.js +19 -0
  49. package/dist/diagnostics.js.map +1 -0
  50. package/dist/emit.d.ts +8 -0
  51. package/dist/emit.d.ts.map +1 -0
  52. package/dist/emit.js +43 -0
  53. package/dist/emit.js.map +1 -0
  54. package/dist/errors.d.ts +22 -0
  55. package/dist/errors.d.ts.map +1 -0
  56. package/dist/errors.js +39 -0
  57. package/dist/errors.js.map +1 -0
  58. package/dist/firmware-class.d.ts +69 -0
  59. package/dist/firmware-class.d.ts.map +1 -0
  60. package/dist/firmware-class.js +20 -0
  61. package/dist/firmware-class.js.map +1 -0
  62. package/dist/fixtures/circuits.d.ts +1721 -0
  63. package/dist/fixtures/circuits.d.ts.map +1 -0
  64. package/dist/fixtures/circuits.js +13404 -0
  65. package/dist/fixtures/circuits.js.map +1 -0
  66. package/dist/fixtures/expected.d.ts +257 -0
  67. package/dist/fixtures/expected.d.ts.map +1 -0
  68. package/dist/fixtures/expected.js +311 -0
  69. package/dist/fixtures/expected.js.map +1 -0
  70. package/dist/fixtures/index.d.ts +4 -0
  71. package/dist/fixtures/index.d.ts.map +1 -0
  72. package/dist/fixtures/index.js +8 -0
  73. package/dist/fixtures/index.js.map +1 -0
  74. package/dist/fixtures/registry.d.ts +52 -0
  75. package/dist/fixtures/registry.d.ts.map +1 -0
  76. package/dist/fixtures/registry.js +341 -0
  77. package/dist/fixtures/registry.js.map +1 -0
  78. package/dist/generic-tube-fit.d.ts +12 -0
  79. package/dist/generic-tube-fit.d.ts.map +1 -0
  80. package/dist/generic-tube-fit.js +45 -0
  81. package/dist/generic-tube-fit.js.map +1 -0
  82. package/dist/grounded-clock-supply.d.ts +13 -0
  83. package/dist/grounded-clock-supply.d.ts.map +1 -0
  84. package/dist/grounded-clock-supply.js +45 -0
  85. package/dist/grounded-clock-supply.js.map +1 -0
  86. package/dist/identify.d.ts +50 -0
  87. package/dist/identify.d.ts.map +1 -0
  88. package/dist/identify.js +319 -0
  89. package/dist/identify.js.map +1 -0
  90. package/dist/index.d.ts +10 -0
  91. package/dist/index.d.ts.map +1 -0
  92. package/dist/index.js +19 -0
  93. package/dist/index.js.map +1 -0
  94. package/dist/inert-controls.d.ts +15 -0
  95. package/dist/inert-controls.d.ts.map +1 -0
  96. package/dist/inert-controls.js +266 -0
  97. package/dist/inert-controls.js.map +1 -0
  98. package/dist/latch-seed.d.ts +53 -0
  99. package/dist/latch-seed.d.ts.map +1 -0
  100. package/dist/latch-seed.js +257 -0
  101. package/dist/latch-seed.js.map +1 -0
  102. package/dist/link.d.ts +7 -0
  103. package/dist/link.d.ts.map +1 -0
  104. package/dist/link.js +270 -0
  105. package/dist/link.js.map +1 -0
  106. package/dist/lower.d.ts +79 -0
  107. package/dist/lower.d.ts.map +1 -0
  108. package/dist/lower.js +1855 -0
  109. package/dist/lower.js.map +1 -0
  110. package/dist/netlist.d.ts +79 -0
  111. package/dist/netlist.d.ts.map +1 -0
  112. package/dist/netlist.js +4746 -0
  113. package/dist/netlist.js.map +1 -0
  114. package/dist/non-executable-clock-drivers.d.ts +8 -0
  115. package/dist/non-executable-clock-drivers.d.ts.map +1 -0
  116. package/dist/non-executable-clock-drivers.js +33 -0
  117. package/dist/non-executable-clock-drivers.js.map +1 -0
  118. package/dist/open-category.d.ts +98 -0
  119. package/dist/open-category.d.ts.map +1 -0
  120. package/dist/open-category.js +111 -0
  121. package/dist/open-category.js.map +1 -0
  122. package/dist/over-driven-node.d.ts +33 -0
  123. package/dist/over-driven-node.d.ts.map +1 -0
  124. package/dist/over-driven-node.js +188 -0
  125. package/dist/over-driven-node.js.map +1 -0
  126. package/dist/part-catalog.d.ts +7 -0
  127. package/dist/part-catalog.d.ts.map +1 -0
  128. package/dist/part-catalog.js +6639 -0
  129. package/dist/part-catalog.js.map +1 -0
  130. package/dist/part-number.d.ts +32 -0
  131. package/dist/part-number.d.ts.map +1 -0
  132. package/dist/part-number.js +80 -0
  133. package/dist/part-number.js.map +1 -0
  134. package/dist/partition.d.ts +7 -0
  135. package/dist/partition.d.ts.map +1 -0
  136. package/dist/partition.js +242 -0
  137. package/dist/partition.js.map +1 -0
  138. package/dist/port-full-scale.d.ts +70 -0
  139. package/dist/port-full-scale.d.ts.map +1 -0
  140. package/dist/port-full-scale.js +235 -0
  141. package/dist/port-full-scale.js.map +1 -0
  142. package/dist/pot-orientation.d.ts +114 -0
  143. package/dist/pot-orientation.d.ts.map +1 -0
  144. package/dist/pot-orientation.js +551 -0
  145. package/dist/pot-orientation.js.map +1 -0
  146. package/dist/power-domain-control.d.ts +40 -0
  147. package/dist/power-domain-control.d.ts.map +1 -0
  148. package/dist/power-domain-control.js +142 -0
  149. package/dist/power-domain-control.js.map +1 -0
  150. package/dist/proxy-declaration.d.ts +121 -0
  151. package/dist/proxy-declaration.d.ts.map +1 -0
  152. package/dist/proxy-declaration.js +50 -0
  153. package/dist/proxy-declaration.js.map +1 -0
  154. package/dist/registry.d.ts +323 -0
  155. package/dist/registry.d.ts.map +1 -0
  156. package/dist/registry.js +192 -0
  157. package/dist/registry.js.map +1 -0
  158. package/dist/sparse-schedule.d.ts +65 -0
  159. package/dist/sparse-schedule.d.ts.map +1 -0
  160. package/dist/sparse-schedule.js +421 -0
  161. package/dist/sparse-schedule.js.map +1 -0
  162. package/dist/speaker-load.d.ts +38 -0
  163. package/dist/speaker-load.d.ts.map +1 -0
  164. package/dist/speaker-load.js +97 -0
  165. package/dist/speaker-load.js.map +1 -0
  166. package/dist/stage-coverage.d.ts +21 -0
  167. package/dist/stage-coverage.d.ts.map +1 -0
  168. package/dist/stage-coverage.js +124 -0
  169. package/dist/stage-coverage.js.map +1 -0
  170. package/dist/stamp-partition.d.ts +314 -0
  171. package/dist/stamp-partition.d.ts.map +1 -0
  172. package/dist/stamp-partition.js +472 -0
  173. package/dist/stamp-partition.js.map +1 -0
  174. package/dist/supply-reference.d.ts +19 -0
  175. package/dist/supply-reference.d.ts.map +1 -0
  176. package/dist/supply-reference.js +66 -0
  177. package/dist/supply-reference.js.map +1 -0
  178. package/dist/supply-short.d.ts +32 -0
  179. package/dist/supply-short.d.ts.map +1 -0
  180. package/dist/supply-short.js +118 -0
  181. package/dist/supply-short.js.map +1 -0
  182. package/dist/supply-stamps.d.ts +51 -0
  183. package/dist/supply-stamps.d.ts.map +1 -0
  184. package/dist/supply-stamps.js +363 -0
  185. package/dist/supply-stamps.js.map +1 -0
  186. package/dist/terminal-role.d.ts +109 -0
  187. package/dist/terminal-role.d.ts.map +1 -0
  188. package/dist/terminal-role.js +46 -0
  189. package/dist/terminal-role.js.map +1 -0
  190. package/dist/terminal-roles.d.ts +59 -0
  191. package/dist/terminal-roles.d.ts.map +1 -0
  192. package/dist/terminal-roles.js +92 -0
  193. package/dist/terminal-roles.js.map +1 -0
  194. package/dist/transformer.d.ts +181 -0
  195. package/dist/transformer.d.ts.map +1 -0
  196. package/dist/transformer.js +476 -0
  197. package/dist/transformer.js.map +1 -0
  198. package/dist/types.d.ts +3157 -0
  199. package/dist/types.d.ts.map +1 -0
  200. package/dist/types.js +11 -0
  201. package/dist/types.js.map +1 -0
  202. package/dist/unbounded-operating-point.d.ts +35 -0
  203. package/dist/unbounded-operating-point.d.ts.map +1 -0
  204. package/dist/unbounded-operating-point.js +181 -0
  205. package/dist/unbounded-operating-point.js.map +1 -0
  206. package/dist/unexecuted-region.d.ts +3 -0
  207. package/dist/unexecuted-region.d.ts.map +1 -0
  208. package/dist/unexecuted-region.js +122 -0
  209. package/dist/unexecuted-region.js.map +1 -0
  210. package/dist/unimplemented-control-role.d.ts +3 -0
  211. package/dist/unimplemented-control-role.d.ts.map +1 -0
  212. package/dist/unimplemented-control-role.js +61 -0
  213. package/dist/unimplemented-control-role.js.map +1 -0
  214. package/dist/unreachable-output.d.ts +3 -0
  215. package/dist/unreachable-output.d.ts.map +1 -0
  216. package/dist/unreachable-output.js +97 -0
  217. package/dist/unreachable-output.js.map +1 -0
  218. package/dist/unreadable-terminal-role.d.ts +67 -0
  219. package/dist/unreadable-terminal-role.d.ts.map +1 -0
  220. package/dist/unreadable-terminal-role.js +409 -0
  221. package/dist/unreadable-terminal-role.js.map +1 -0
  222. package/dist/unverified-pinout.d.ts +27 -0
  223. package/dist/unverified-pinout.d.ts.map +1 -0
  224. package/dist/unverified-pinout.js +121 -0
  225. package/dist/unverified-pinout.js.map +1 -0
  226. package/package.json +75 -5
@@ -0,0 +1,551 @@
1
+ // Which end of a potentiometer is the quiet one, split out of `lower.ts` (R7, 2026-09-01).
2
+ //
3
+ // A pot's law is a track resistance split by its 0..1 position, so lowering needs to know
4
+ // which declared end the position counts *from*.
5
+ //
6
+ // **The format CAN state it, and since 2026-09-22 the declaration is read first.**
7
+ // `@vessel-dsp/core` owns `PotentiometerTerminalRole = ccw | wiper | cw` -- rotation, not
8
+ // position, so it survives mirroring -- and its resolver refuses rather than guessing, saying
9
+ // of an incomplete one: *"the source does not carry the sweep direction. Do not infer it."*
10
+ // This module inferred it for every pot regardless, including the 15 in the corpus that
11
+ // declare both ends, and disagreed with 4 of them. See `declaredEnds`.
12
+ //
13
+ // The inference remains, because 348 of the corpus's 363 pots declare `end` -- core's
14
+ // deliberately ambiguous token -- and something has to orient them: a BFS over DC-conducting
15
+ // devices measures each end's distance to ground and to an op-amp input, and the closer-to-
16
+ // ground end is the quiet one. That is inference over inference, and every one of those 348 is
17
+ // a packet backfill waiting to retire a branch of it -- see R1 in
18
+ // `thoughts/shared/plans/archive/2026-08-31-v2-complexity-reduction-plan.md`.
19
+ import { LoweringError } from "./errors.js";
20
+ import { dcConductingKinds } from "./netlist.js";
21
+ import { GROUND } from "./types.js";
22
+ /**
23
+ * The one terminal index whose **declared** role is `wiper`, or null when the terminals disagree.
24
+ *
25
+ * Several terminals may declare it and still be unambiguous: `boss-dm-3`'s `VR1` writes
26
+ * `lug1,lug2,lug3,wiper` with `lug2` and `wiper` on one node -- the same physical point named
27
+ * twice -- so what matters is that every `wiper` resolves to the same node, not that only one
28
+ * terminal says so. Two *different* nodes claiming it is a document this stage cannot read.
29
+ */
30
+ function declaredWiperIndex(device) {
31
+ const declared = device.identity.declaredTerminalRoles;
32
+ const indices = declared.flatMap((role, index) => role === "wiper" ? [index] : []);
33
+ if (indices.length === 0) {
34
+ return null;
35
+ }
36
+ const nodes = new Set(indices.map((index) => device.nodes[index]));
37
+ return nodes.size === 1 ? (indices[0] ?? null) : null;
38
+ }
39
+ /**
40
+ * The two nodes a device declares as its `ccw` and `cw` ends, or null when it does not say.
41
+ *
42
+ * **`@vessel-dsp/core` owns this vocabulary and everything below is the guess it replaces.**
43
+ * `PotentiometerTerminalRole` is `ccw | wiper | cw`, rotation and not position, so it survives
44
+ * mirroring and board rotation; the resolver refuses rather than completes, and its own doc
45
+ * comment says of an incomplete resolution: *"False means the source does not carry the sweep
46
+ * direction. Do not infer it."* Inferring it is exactly what this file did, for every pot,
47
+ * including the ones that said.
48
+ *
49
+ * Measured over the corpus 2026-09-22: **363 pots, 15 declare both ends, 348 declare
50
+ * `end`** -- core's ambiguous token, which resolves to no role by design. So the quiet-distance
51
+ * inference below is still what almost every pot gets, and that is the *second* half of the
52
+ * typed-source-evidence test: the source can state the fact and does not, which makes those 348
53
+ * a packet backfill in `vessel-dsp/artifacts` rather than anything to fix here.
54
+ *
55
+ * On the 15 that do declare, the inference **agreed on 11 and disagreed on 4** --
56
+ * `electro-harmonix-frequency-analyzer`'s `P1_BLEND` and `P2_FINE_TUNE`, and
57
+ * `moogerfooger-mf-102`'s `P1` and `VR2`. Those four knobs swept backwards, and the packets had
58
+ * said so all along. A conflict is resolved in favour of the declaration, because the
59
+ * alternative is this repository overruling a typed source fact with a circuit guess.
60
+ *
61
+ * Both ends must resolve to one node each and the two must differ; anything else is not a
62
+ * declaration this stage can read, and falls through to the inference.
63
+ */
64
+ function declaredEnds(device) {
65
+ const declared = device.identity.declaredTerminalRoles;
66
+ const nodesFor = (role) => new Set(declared.flatMap((declaredRole, index) => declaredRole === role ? [device.nodes[index]] : []));
67
+ const ccw = nodesFor("ccw");
68
+ const cw = nodesFor("cw");
69
+ if (ccw.size !== 1 || cw.size !== 1) {
70
+ return null;
71
+ }
72
+ const [ccwNode] = [...ccw];
73
+ const [cwNode] = [...cw];
74
+ if (ccwNode === undefined || cwNode === undefined || ccwNode === cwNode) {
75
+ return null;
76
+ }
77
+ return [ccwNode, cwNode];
78
+ }
79
+ /**
80
+ * Adjacency among nodes joined by a DC-conducting device -- the closed `dcConductingKinds`
81
+ * vocabulary (resistor, potentiometer, rheostat, inductor, switch, selector) `netlist.ts`'s
82
+ * `voltagePortRails` also uses. Shared by every quiet-distance BFS in this file, computed once
83
+ * per netlist rather than once per seed set: the graph does not change between them.
84
+ */
85
+ function dcConductingAdjacency(netlist,
86
+ /**
87
+ * Kinds to conduct in addition to `dcConductingKinds`. Empty by default (pure DC graph,
88
+ * the behaviour every existing caller relies on); a caller asking an AC-connectivity
89
+ * question passes the kinds it wants added, e.g. `"capacitor"`.
90
+ */
91
+ extraKinds = new Set()) {
92
+ const conducts = (kind) => dcConductingKinds.has(kind) || extraKinds.has(kind);
93
+ const adjacency = new Map();
94
+ for (const device of netlist.devices) {
95
+ if (!conducts(device.kind)) {
96
+ continue;
97
+ }
98
+ for (let i = 0; i < device.nodes.length; i += 1) {
99
+ for (let j = i + 1; j < device.nodes.length; j += 1) {
100
+ const a = device.nodes[i];
101
+ const b = device.nodes[j];
102
+ if (a === b) {
103
+ continue;
104
+ }
105
+ adjacency.set(a, [...(adjacency.get(a) ?? []), b]);
106
+ adjacency.set(b, [...(adjacency.get(b) ?? []), a]);
107
+ }
108
+ }
109
+ }
110
+ return adjacency;
111
+ }
112
+ /**
113
+ * Multi-source BFS over a DC-conducting adjacency graph: every seed starts at distance 0, so the
114
+ * result is each reachable node's distance to its *nearest* seed.
115
+ */
116
+ function bfsDistances(adjacency, seeds) {
117
+ const distance = new Map();
118
+ const queue = [];
119
+ for (const node of seeds) {
120
+ distance.set(node, 0);
121
+ queue.push(node);
122
+ }
123
+ let head = 0;
124
+ while (head < queue.length) {
125
+ const at = queue[head];
126
+ head += 1;
127
+ const atDistance = distance.get(at);
128
+ for (const next of adjacency.get(at) ?? []) {
129
+ if (!distance.has(next)) {
130
+ distance.set(next, atDistance + 1);
131
+ queue.push(next);
132
+ }
133
+ }
134
+ }
135
+ return distance;
136
+ }
137
+ /**
138
+ * How far each node sits, in hops through DC-conducting devices, from a quiet DC reference --
139
+ * ground, or a supply's own terminal.
140
+ *
141
+ * This is the connectivity evidence a pot's orientation needs, in the same closed vocabulary
142
+ * `netlist.ts`'s `voltagePortRails` already uses to ask a related question ("is this node's
143
+ * potential already generated"): `dcConductingKinds` -- resistor, potentiometer, rheostat,
144
+ * inductor, switch, selector -- conduct a steady current, and nothing else in this set does, so
145
+ * an active device (a transistor, an op-amp, a diode) is never crossed. A quiet reference is
146
+ * ground itself or any terminal of a `voltage-source` or `rail` device -- **not** an op-amp
147
+ * output, which is actively driven with the signal and is the opposite of quiet.
148
+ *
149
+ * Computed once per netlist and passed down, not per pot: `boss-ds-1` alone lowers 82 regions,
150
+ * and the graph does not change between them.
151
+ */
152
+ export function quietDistances(netlist) {
153
+ const quietReferences = new Set([GROUND]);
154
+ for (const device of netlist.devices) {
155
+ if (device.kind === "voltage-source" || device.kind === "rail") {
156
+ for (const node of device.nodes) {
157
+ quietReferences.add(node);
158
+ }
159
+ }
160
+ }
161
+ return bfsDistances(dcConductingAdjacency(netlist), quietReferences);
162
+ }
163
+ /**
164
+ * An op-amp input seeds the quiet-distance BFS this file uses for pot orientation, and it is read
165
+ * from the declared role rather than from a folded terminal name.
166
+ *
167
+ * The name vocabulary this replaced had to be kept in step with
168
+ * `scripts/lib/source-to-spice.ts`, which uses the same seeds for the from-source parity deck: a
169
+ * stale copy there makes the deck disagree with the pipeline about which end of a pot is quiet,
170
+ * and the parity report reads that tool artefact as a source defect. One field, read the same way
171
+ * in both, removes that coupling.
172
+ */
173
+ function isOpampInput(role) {
174
+ return role === "nonInverting" || role === "inverting";
175
+ }
176
+ /**
177
+ * How far each node sits, in hops through DC-conducting devices, from an op-amp's own input
178
+ * terminal.
179
+ *
180
+ * A second, narrower quiet-reference class than `quietDistances`, kept separate rather than
181
+ * folded into it. An op-amp input under closed-loop negative feedback sits at a virtual
182
+ * reference regardless of the feedback network's own resistances -- a property of the feedback
183
+ * *topology*, not of any one element's value -- so seeding it is not the same evidence-standing-
184
+ * on-itself risk `netlist.ts`'s `generated()` was found to have (there, an op-amp's *output* was
185
+ * treated as an independent reference, which a feedback path can make circular: the output's own
186
+ * potential depends on the input it would be certifying). Measured 2026-08-14 (the rheostat-nine
187
+ * census, `docs/todo-archive/2026-08-14-the-rheostat-nine.md`): applied unconditionally, this
188
+ * evidence moves 24 pots, 15 of them reversing an orientation `quietDistances` alone already
189
+ * decided -- including undoing a same-day correction and overturning a pot where declaration
190
+ * order and connectivity previously agreed unanimously. `potTerminals` below therefore only
191
+ * consults this map when `quietDistances` leaves a pot's two ends **fully unreachable** (both
192
+ * infinite) -- never to override an already-finite decision, even a finite tie. Scoped that way,
193
+ * it moves exactly 6 pots and reverses none.
194
+ */
195
+ export function opampInputDistances(netlist) {
196
+ const seeds = new Set();
197
+ for (const device of netlist.devices) {
198
+ if (device.kind !== "opamp") {
199
+ continue;
200
+ }
201
+ device.identity.declaredTerminalRoles.forEach((role, index) => {
202
+ if (isOpampInput(role)) {
203
+ const node = device.nodes[index];
204
+ if (node !== undefined) {
205
+ seeds.add(node);
206
+ }
207
+ }
208
+ });
209
+ }
210
+ return bfsDistances(dcConductingAdjacency(netlist), seeds);
211
+ }
212
+ /**
213
+ * How far each node sits, in hops through DC-conducting devices, from an op-amp's declared
214
+ * **output** terminal.
215
+ *
216
+ * The companion of `opampInputDistances` for the negative-feedback gain-stage class: a rheostat
217
+ * wired from an op-amp's declared output, through its track, to the same op-amp's declared
218
+ * inverting input is a gain-setting feedback element, and for that class a rising control must
219
+ * mean *more* feedback resistance (non-inverting gain is `1 + Rf/Rg`, so more `Rf` is more
220
+ * gain). `boss-os-2`'s `DRIVE` sits exactly there on both its 270 k sections: the wiper shares
221
+ * its node with the `output` terminal, the free end reaches the `inverting` terminal through a
222
+ * single series resistor, and the whole pocket is DC-isolated from ground, so
223
+ * `quietDistances` has no claim and the `opampInputDistances` tie above falls through to
224
+ * declaration order -- which oriented `VR3b` so its live resistance *fell* as the knob rose,
225
+ * running the pedal's Drive backwards (rendered: 6.3e-1 rms at 0.0 against 2.9e-1 at 1.0).
226
+ * The output-side distance below is the discriminating typed fact: which end the wiper is
227
+ * strapped to relative to the declared `output` role, not how close either end happens to sit
228
+ * to an input.
229
+ */
230
+ export function opampOutputDistances(netlist) {
231
+ const seeds = new Set();
232
+ for (const device of netlist.devices) {
233
+ if (device.kind !== "opamp") {
234
+ continue;
235
+ }
236
+ device.identity.declaredTerminalRoles.forEach((role, index) => {
237
+ if (role === "output") {
238
+ const node = device.nodes[index];
239
+ if (node !== undefined) {
240
+ seeds.add(node);
241
+ }
242
+ }
243
+ });
244
+ }
245
+ return bfsDistances(dcConductingAdjacency(netlist), seeds);
246
+ }
247
+ /**
248
+ * The set of nodes that are a declared op-amp **inverting** input, read from the declared
249
+ * `inverting` role rather than a folded terminal name (the same closed-vocabulary read
250
+ * `opampInputDistances` uses for its seeds, narrowed to the inverting half).
251
+ *
252
+ * Kept as a node set, not a distance map, because the one consumer below asks a yes/no
253
+ * question -- "does this pot's wiper sit on an inverting input?" -- not "how far is it from
254
+ * one". `opampInputDistances` cannot answer that: it seeds from *both* input roles, so a zero
255
+ * there does not say which input a node sits on.
256
+ */
257
+ export function opampInvertingInputNodes(netlist) {
258
+ const nodes = new Set();
259
+ for (const device of netlist.devices) {
260
+ if (device.kind !== "opamp") {
261
+ continue;
262
+ }
263
+ device.identity.declaredTerminalRoles.forEach((role, index) => {
264
+ if (role === "inverting") {
265
+ const node = device.nodes[index];
266
+ if (node !== undefined) {
267
+ nodes.add(node);
268
+ }
269
+ }
270
+ });
271
+ }
272
+ return nodes;
273
+ }
274
+ /**
275
+ * How far each node sits, in hops through the **AC** graph (DC-conducting devices *plus*
276
+ * capacitors), from an op-amp's declared output terminal.
277
+ *
278
+ * The companion of `opampOutputDistances` for the one shape it cannot reach: a non-inverting
279
+ * gain pot whose wiper sits *on* the op-amp's declared inverting input. For that class the wiper
280
+ * is the DC hub -- both track ends reach ground, the inverting input, and the output through the
281
+ * wiper in exactly the same number of DC hops -- so every DC distance map this file has is a
282
+ * tie and is silent about which end the live half is. Capacitors are the one passive element
283
+ * that separates the two ends in that shape (the output couples to one end, ground to the
284
+ * other), so the discrimination has to follow them. `boss-ds-1`'s `VR1` is the corpus's sole
285
+ * instance: its two ends are a 2/2 DC-quiet tie, the wiper is on the inverting input, and
286
+ * only `AC` separates the output-coupled end (one cap, `C6`, from the output) from the
287
+ * ground-coupled end.
288
+ *
289
+ * Computed over the AC graph on purpose, not by adding a capacitor-aware variant to the DC
290
+ * maps: the DC maps are a validated "moves exactly 6 pots, reverses none" instrument and must
291
+ * stay DC, and folding a capacitor into them would change what every existing caller reads.
292
+ */
293
+ export function opampOutputAcDistances(netlist) {
294
+ const seeds = new Set();
295
+ for (const device of netlist.devices) {
296
+ if (device.kind !== "opamp") {
297
+ continue;
298
+ }
299
+ device.identity.declaredTerminalRoles.forEach((role, index) => {
300
+ if (role === "output") {
301
+ const node = device.nodes[index];
302
+ if (node !== undefined) {
303
+ seeds.add(node);
304
+ }
305
+ }
306
+ });
307
+ }
308
+ return bfsDistances(dcConductingAdjacency(netlist, new Set(["capacitor"])), seeds);
309
+ }
310
+ /**
311
+ * Control roles that name a time constant rather than a level.
312
+ *
313
+ * `potTerminals`' quiet-distance rule exists to make a rising control mean "louder", which is
314
+ * the right goal for a gain or volume pot and an empty one for a pot setting an RC. Measured on
315
+ * `boss-nf-1-noise-gate`'s `DECAY`: the two orientations render the *same* output level at both
316
+ * ends of the sweep, so the loudness evidence says nothing and the rule picks arbitrarily -- it
317
+ * picked the side that runs the knob backwards, giving a 240 ms release at full clockwise where
318
+ * the ET-45C service note's ADJUSTMENT block sets DECAY full clockwise for its 1.5-2 s decay.
319
+ *
320
+ * **Why a positive list and not "every rheostat".** Letting declaration order win for all 64 of
321
+ * the corpus's rheostat-shaped pots was measured and is worse: it inverts three knobs that are
322
+ * currently right to fix one that is wrong. `boss-fa-1`'s `VOLUME` goes from 6.4e-7 -> 9.3e-1
323
+ * across its sweep today and 9.3e-1 -> 6.4e-7 under that change, so turning the volume up would
324
+ * mute the pedal; `bk-butler-tube-driver`'s `TUBE_DRIVE` and `boss-od-1`'s `OVER_DRIVE` invert
325
+ * the same way. The quiet-distance rule is load-bearing for those and must keep them.
326
+ *
327
+ * So the exemption is scoped to roles that name a time constant, where "louder" is not what the
328
+ * knob is for. Roles are free text in this corpus and most pots declare none at all -- including
329
+ * `TUBE_DRIVE` and every Marshall tone pot -- so an unrecognised or absent role keeps today's
330
+ * behaviour, which is the safe default.
331
+ */
332
+ const TIME_CONSTANT_CONTROL_ROLES = new Set([
333
+ "decay",
334
+ "attack",
335
+ "release",
336
+ "time",
337
+ "d.time",
338
+ "r.time",
339
+ "rate",
340
+ "lfo-rate",
341
+ "speed",
342
+ "rise",
343
+ "rise/fall",
344
+ ]);
345
+ function namesATimeConstant(role) {
346
+ return role == null
347
+ ? false
348
+ : TIME_CONSTANT_CONTROL_ROLES.has(role.trim().toLowerCase());
349
+ }
350
+ export function potTerminals(device, quietDistance, opampInputDistance,
351
+ /**
352
+ * Distance to an op-amp's declared output terminal, for the negative-feedback
353
+ * gain-stage tie below. Empty by default: a call site that has no netlist in hand
354
+ * (the inert-control and operating-point screens) passes nothing and gets today's
355
+ * behaviour exactly, as with the other two maps.
356
+ */
357
+ opampOutputDistance = new Map(),
358
+ /**
359
+ * The declared role of the control that varies this pot, when the document states one.
360
+ * Only consulted for the rheostat exemption below; every other path ignores it, and a
361
+ * call site that has no role passes `null` and gets today's behaviour exactly.
362
+ */
363
+ controlRole = null,
364
+ /**
365
+ * Nodes that are a declared op-amp inverting input, for the negative-feedback gain-pot
366
+ * tie below. Empty by default: a call site with no netlist in hand (the inert-control and
367
+ * operating-point screens) passes nothing and gets today's behaviour exactly, as with the
368
+ * other evidence maps.
369
+ */
370
+ invertingInputNodes = new Set(),
371
+ /**
372
+ * AC distance (DC + capacitors) to an op-amp's declared output, for the same gain-pot
373
+ * tie. Empty by default for the same reason.
374
+ */
375
+ acOutputDistance = new Map()) {
376
+ // Find the wiper by role, not by sitting in the middle. 81 of the corpus's 331
377
+ // three-terminal pots declare it first or last -- `anode,cathode,wiper` alone is
378
+ // 64 -- and taking position 2 regardless makes whatever is there the wiper. When
379
+ // that is the grounded end, both halves of the track short to ground, the output
380
+ // is cut off from the input, and the pedal renders **exact silence**.
381
+ // **Read from the declared role, and refuse rather than fall back.** This matched a folded
382
+ // terminal *name* against `{wiper, wipe, w}` and took declaration order when nothing matched,
383
+ // which is the silent half of the role-vocabulary problem: a document naming its wiper
384
+ // anything else got position 2 regardless, and nothing said so. Measured across the corpus
385
+ // after the roles were backfilled: 523 of 523 pots reaching this resolve by declared role, 0
386
+ // declare none, 0 are ambiguous -- so the positional path had no remaining legitimate case
387
+ // and is a refusal instead.
388
+ const wiperIndex = declaredWiperIndex(device);
389
+ if (wiperIndex === null) {
390
+ const declared = device.identity.declaredTerminalRoles;
391
+ throw new LoweringError(`potentiometer ${device.id} does not identify its wiper: ${declared.some((role) => role === "wiper")
392
+ ? "several terminals declare `wiper` on different nodes"
393
+ : "no terminal declares `wiper`"} (roles [${declared.join(", ")}]) -- and taking the middle terminal instead shorts ` +
394
+ "both halves of the track to whatever sits there, which renders exact silence", device.id);
395
+ }
396
+ const ends = device.nodes.filter((_, index) => index !== wiperIndex);
397
+ const wiper = device.nodes[wiperIndex];
398
+ const [declaredFirst, declaredSecond] = ends;
399
+ if (declaredFirst === undefined ||
400
+ wiper === undefined ||
401
+ declaredSecond === undefined) {
402
+ throw new LoweringError(`potentiometer ${device.id} needs three terminals`, device.id);
403
+ }
404
+ // The stamps below put `end1`-to-wiper on the side whose share *shrinks* toward the wiper's
405
+ // travel and `end2`-to-wiper on the side whose share *grows* with it (see `lowerRegion`'s
406
+ // `controlled-conductance` case and the runtime's identical `fraction` comment) -- so `end2`
407
+ // has to be the electrically quiet end for a rising control position to mean "louder",
408
+ // which is a fact about the circuit, not about which terminal a schematic happened to list
409
+ // first.
410
+ //
411
+ // Evidence, never declaration order: whichever declared end sits closer to a quiet DC
412
+ // reference (ground, or a supply's own terminal) becomes `end2`. A tie -- both equidistant,
413
+ // including both unreachable -- is not evidence either way, so it falls back to declaration
414
+ // order exactly as before, which is what the corpus's other pots that already work this way
415
+ // (248 of them, before this change) rely on unchanged.
416
+ // **A declaration outranks every inference below.** `end2` is the end the wiper sits at when
417
+ // the control reads 0 -- it takes the `lower` stamp, whose share is `fraction` itself, so its
418
+ // half collapses to the residual at position 0 -- and position 0 is the shaft fully
419
+ // counter-clockwise. So `end2` is the `ccw` lug whenever the document names it, and nothing
420
+ // after this point is consulted. See `declaredEnds`.
421
+ //
422
+ // **Including a rheostat**, whose wiper is strapped to one of its own declared ends. That
423
+ // shape has no divider and the existing fallback for it reads the *control's* free-text role
424
+ // against a spelling table (`TIME_CONSTANT_CONTROL_ROLES`), which is prose matching on the
425
+ // lowering spine. A declared rotation is the typed fact that table stands in for, so it wins
426
+ // here too, and the arithmetic comes out right either way: with the wiper on `cw`, `end2` is
427
+ // `ccw` and the live half takes `share = fraction`, so its resistance grows as the shaft
428
+ // turns clockwise; with the wiper on `ccw`, the live half is `end1`'s and takes
429
+ // `1 - fraction`, and it shrinks. Both are what the shaft does.
430
+ // `electro-harmonix-frequency-analyzer`'s `P2_FINE_TUNE` and `moogerfooger-mf-102`'s `P1`
431
+ // are the corpus's two, and both ran backwards under the inference.
432
+ const declaredRotation = declaredEnds(device);
433
+ if (declaredRotation !== null) {
434
+ const [ccwNode, cwNode] = declaredRotation;
435
+ return [cwNode, wiper, ccwNode];
436
+ }
437
+ // A rheostat -- wiper strapped to one of its own ends -- has no divider to orient, and when
438
+ // its control names a time constant the quiet-distance rule below has no loudness signal to
439
+ // read. Which declared end the wiper is strapped to is then the only evidence there is, so
440
+ // declaration order wins here and nowhere else. See `TIME_CONSTANT_CONTROL_ROLES`.
441
+ if ((wiper === declaredFirst || wiper === declaredSecond) &&
442
+ namesATimeConstant(controlRole)) {
443
+ return [declaredFirst, wiper, declaredSecond];
444
+ }
445
+ const firstDistance = quietDistance.get(declaredFirst) ?? Number.POSITIVE_INFINITY;
446
+ const secondDistance = quietDistance.get(declaredSecond) ?? Number.POSITIVE_INFINITY;
447
+ if (Number.isFinite(firstDistance) || Number.isFinite(secondDistance)) {
448
+ if (firstDistance < secondDistance) {
449
+ return [declaredSecond, wiper, declaredFirst];
450
+ }
451
+ if (secondDistance < firstDistance) {
452
+ return [declaredFirst, wiper, declaredSecond];
453
+ }
454
+ // A finite tie (both ends the same non-infinite distance, e.g. `boss-ph-1r`'s `VR2` at
455
+ // 3/3) is still real evidence that *something* about the graph already reaches both ends
456
+ // equally -- narrower and more reliable than "nothing reaches either", so it is left on
457
+ // declaration order rather than handed to the op-amp-input fallback below, which is
458
+ // scoped to the fully-unreachable case only.
459
+ //
460
+ // One exception, and only one: a non-inverting gain pot whose wiper sits on the op-amp's
461
+ // declared inverting input. For that shape the wiper is the DC hub, so the quiet, input,
462
+ // and output DC distances all tie exactly as here, and every DC map this file has is
463
+ // silent about which end the live half is -- declaration order decides, and it orients
464
+ // the live half backwards when the schematic lists the output-coupled end first.
465
+ // `boss-ds-1`'s `VR1` is the corpus's sole instance: rendered 3.0e-2 rms at 0.0 against
466
+ // 1.9e-2 at 1.0, its Drive running backwards. The one typed fact that separates the two
467
+ // ends there is AC connectivity -- the output couples (through a capacitor) to one end,
468
+ // ground to the other -- so when the wiper is on a declared inverting input and the ends
469
+ // differ in AC output distance, the end nearer the output becomes `end2`: its live half
470
+ // is the `lower` stamp (`share = fraction`), so a rising control adds feedback resistance
471
+ // (non-inverting gain is `1 + Rf/Rg`) and means more gain. A plain tie with no such
472
+ // discrimination stays on declaration order, as before; a tie where the wiper is not on
473
+ // an inverting input is left alone here and falls to its own existing evidence.
474
+ if (invertingInputNodes.has(wiper)) {
475
+ const acFirst = acOutputDistance.get(declaredFirst) ?? Number.POSITIVE_INFINITY;
476
+ const acSecond = acOutputDistance.get(declaredSecond) ?? Number.POSITIVE_INFINITY;
477
+ if (acFirst < acSecond) {
478
+ return [declaredSecond, wiper, declaredFirst];
479
+ }
480
+ if (acSecond < acFirst) {
481
+ return [declaredFirst, wiper, declaredSecond];
482
+ }
483
+ }
484
+ return [declaredFirst, wiper, declaredSecond];
485
+ }
486
+ // Both ends fully unreachable from ground/rail: `quietDistances` has made no claim at all
487
+ // about this pot. Op-amp-input evidence is trustworthy here only for a pot that is *also*
488
+ // structurally wired as a rheostat -- its wiper coincident with one of its own ends
489
+ // (`boss-fa-1`'s `VR1` shape), or the wiper declared at the quiet reference itself
490
+ // (`boss-hm-2`'s `VR4_DIST` shape) -- the same working detector the 2026-08-14 rheostat-nine
491
+ // census validated. An ordinary three-terminal divider that merely floats in a DC-isolated
492
+ // pocket for unrelated reasons (a real, separate wiper node, no rheostat shape at all) does
493
+ // not get this evidence: measured against `jhs-morning-glory`'s `Drive` (exactly this
494
+ // ordinary-divider shape, not wiper-coincident), letting it through moved the pot's own
495
+ // already-marginal Newton operating point from a bounded reading at one end of its travel to
496
+ // a diverging one (peak ~8e3 against a 0.1 V input) at the other -- a measured regression,
497
+ // not a structural inference, and the reason this gate exists rather than trusting "both
498
+ // ends unreachable" alone.
499
+ const wiperIsRheostatShaped = wiper === declaredFirst ||
500
+ wiper === declaredSecond ||
501
+ quietDistance.get(wiper) === 0;
502
+ if (!wiperIsRheostatShaped) {
503
+ return [declaredFirst, wiper, declaredSecond];
504
+ }
505
+ const firstOpampDistance = opampInputDistance.get(declaredFirst) ?? Number.POSITIVE_INFINITY;
506
+ const secondOpampDistance = opampInputDistance.get(declaredSecond) ?? Number.POSITIVE_INFINITY;
507
+ if (firstOpampDistance < secondOpampDistance) {
508
+ return [declaredSecond, wiper, declaredFirst];
509
+ }
510
+ if (secondOpampDistance < firstOpampDistance) {
511
+ return [declaredFirst, wiper, declaredSecond];
512
+ }
513
+ // The input distances tie, so the nearest-input evidence is silent about which end is
514
+ // quiet, and what used to be left was declaration order. Before falling back to it, ask
515
+ // the one typed fact the format does state for the negative-feedback gain-stage class:
516
+ // a rheostat whose wiper is strapped to the end sitting on an op-amp's declared
517
+ // **output**, with the free end reaching that op-amp's declared **inverting** input, is
518
+ // a gain-setting feedback element (non-inverting gain is `1 + Rf/Rg`), and for that
519
+ // class a rising control must mean *more* feedback resistance -- so the live half has
520
+ // to be the `lower` stamp, `share = fraction`. Declaration order got this backwards for
521
+ // `boss-os-2`'s `VR3b` (wiper strapped to the `output` node, `inverting` one hop away
522
+ // through R22): its live half landed on `upper`, where `share = 1 - fraction`, so the
523
+ // pedal's Drive ran backwards -- 6.3e-1 rms at 0.0 against 2.9e-1 at 1.0 -- while its
524
+ // gang twin `VR3a`, decided by `quietDistances` above, was already right.
525
+ //
526
+ // Scoped to the tie on purpose, like the input-distance evidence it guards: the
527
+ // asymmetric case above is the validated "moves exactly 6 pots and reverses none"
528
+ // evidence, and this rule does not override a finite decision it already made. The
529
+ // asymmetry guards (`outEout < outEfree`, `inEfree <= inEout`) keep the class narrow:
530
+ // the wiper-strapped end must be the one nearer a declared output, and the free end at
531
+ // least as near a declared inverting input. Both distances read declared roles and
532
+ // connectivity only; nothing here reads a name.
533
+ if (wiper === declaredFirst || wiper === declaredSecond) {
534
+ const outputEnd = wiper === declaredFirst ? declaredFirst : declaredSecond;
535
+ const freeEnd = wiper === declaredFirst ? declaredSecond : declaredFirst;
536
+ if (outputEnd !== freeEnd) {
537
+ const outEout = opampOutputDistance.get(outputEnd) ?? Number.POSITIVE_INFINITY;
538
+ const outFree = opampOutputDistance.get(freeEnd) ?? Number.POSITIVE_INFINITY;
539
+ const inFree = opampInputDistance.get(freeEnd) ?? Number.POSITIVE_INFINITY;
540
+ const inEout = opampInputDistance.get(outputEnd) ?? Number.POSITIVE_INFINITY;
541
+ if (Number.isFinite(outEout) &&
542
+ outEout < outFree &&
543
+ Number.isFinite(inFree) &&
544
+ inFree <= inEout) {
545
+ return [outputEnd, wiper, freeEnd];
546
+ }
547
+ }
548
+ }
549
+ return [declaredFirst, wiper, declaredSecond];
550
+ }
551
+ //# sourceMappingURL=pot-orientation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pot-orientation.js","sourceRoot":"","sources":["../src/pot-orientation.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,40 @@
1
+ import type { CompileWarning, Netlist, NodeId } from "./types";
2
+ /**
3
+ * A device exposed as a sweepable user control that is **power-domain hardware**: it sits outside
4
+ * the audio graph and no panel entry claims it.
5
+ *
6
+ * **Why this is reported rather than decided.** Structure cannot tell a user control from fixed
7
+ * hardware on this side of the boundary. A standby switch and a mains fuse are both switches in
8
+ * the supply, and one belongs on the front panel while the other belongs inside the chassis --
9
+ * only the document can say which. So the compiler names the ambiguity and the fix is a
10
+ * `deviceInterface.controls` entry, or a kind that is not a switch.
11
+ *
12
+ * **A rule was attempted and it does not exist.** The promising one was "a switch declaring a
13
+ * `FuseRating` is a fuse, therefore not a control" -- legal evidence, since it reads the presence
14
+ * of a typed property rather than a name, and 26 corpus switches declare one. It fails on its own
15
+ * data: `mesa-boogie-dual-rectifier`'s `SRC_POWER_SWITCH_FUSE_4A`, `orange-rockerverb`'s
16
+ * `SRC_PRIMARY_POWER_SWITCH_AND_FUSE` and `sunn-beta-lead`'s `SRC_POWER_SWITCH_FUSE` are each a
17
+ * power switch *and* a fuse in one two-terminal component, and a power switch is exactly the user
18
+ * control the rule would have suppressed. Narrowing it to "two terminals and no switch-shaped
19
+ * property" keeps all three, because a fuse and a combined switch-and-fuse are structurally
20
+ * identical: two terminals, one closed contact. The difference is whether a human operates it,
21
+ * which is not a fact about the circuit.
22
+ *
23
+ * **Measured 2026-09-04: 67 of the corpus's 958 program controls**, across the packets that
24
+ * model their own power supply. It read 80 before `boss-bf-2`'s three service trims were
25
+ * declared, and 76 before every signal jack became a seed -- see the note in the function. They are mains switches,
26
+ * voltage selectors, and mains, HT and heater fuses -- `vox-ac30-top-boost` alone contributes
27
+ * `SW_MAINS`, a 230/120 selector and four fuses. A fuse offered to a player as a knob to sweep is
28
+ * the shape of the problem.
29
+ *
30
+ * **The traversal's one known imprecision** is at the B+ boundary: it stops at the transformer but
31
+ * not at the rectifier and filter, so B+ nodes stay reachable through a tube's plate. That keeps
32
+ * `SW1_STANDBY` and `S_STANDBY_SWITCH` out of this warning, which is right -- a standby switch is
33
+ * a front-panel control -- and also keeps `F2_HT_FUSE` out, which is not.
34
+ */
35
+ export declare function findPowerDomainControls(netlist: Netlist, controls: readonly {
36
+ readonly id: string;
37
+ readonly role?: string | null;
38
+ readonly label?: string | null;
39
+ }[], ports: readonly NodeId[]): readonly CompileWarning[];
40
+ //# sourceMappingURL=power-domain-control.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"power-domain-control.d.ts","sourceRoot":"","sources":["../src/power-domain-control.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAU,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAgEvE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAgB,uBAAuB,CACtC,OAAO,EAAE,OAAO,EAIhB,QAAQ,EAAE,SAAS;IAClB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B,EAAE,EACH,KAAK,EAAE,SAAS,MAAM,EAAE,GACtB,SAAS,cAAc,EAAE,CAkD3B"}