@tangle-network/agent-bench 0.8.0 → 0.8.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/HARNESS.md +1 -1
- package/dist/adapters.js +4 -0
- package/dist/adapters.js.map +1 -1
- package/dist/benchmarks/mcad-bench.d.ts +106 -0
- package/dist/benchmarks/mcad-bench.js +569 -0
- package/dist/benchmarks/mcad-bench.js.map +1 -0
- package/dist/benchmarks/mcad-cq-bench.d.ts +82 -0
- package/dist/benchmarks/mcad-cq-bench.js +339 -0
- package/dist/benchmarks/mcad-cq-bench.js.map +1 -0
- package/dist/benchmarks/mcad-cq-golds.d.ts +36 -0
- package/dist/benchmarks/mcad-cq-golds.js +342 -0
- package/dist/benchmarks/mcad-cq-golds.js.map +1 -0
- package/dist/benchmarks/mcad-golds.d.ts +20 -0
- package/dist/benchmarks/mcad-golds.js +318 -0
- package/dist/benchmarks/mcad-golds.js.map +1 -0
- package/dist/benchmarks/mcad-tasks.d.ts +66 -0
- package/dist/benchmarks/mcad-tasks.js +508 -0
- package/dist/benchmarks/mcad-tasks.js.map +1 -0
- package/package.json +4 -4
- package/src/adapters.ts +11 -0
- package/src/benchmarks/mcad-bench.test.mts +455 -0
- package/src/benchmarks/mcad-bench.ts +561 -0
- package/src/benchmarks/mcad-cq-bench.ts +423 -0
- package/src/benchmarks/mcad-cq-golds.ts +374 -0
- package/src/benchmarks/mcad-cq.test.mts +386 -0
- package/src/benchmarks/mcad-golds.ts +359 -0
- package/src/benchmarks/mcad-tasks.ts +490 -0
- package/src/swe-arena/gepa-seat.mts +1 -1
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
//#region src/benchmarks/mcad-cq-golds.ts
|
|
2
|
+
/**
|
|
3
|
+
* MCAD-CQ gold oracles — one Python CadQuery script per task in `mcad-tasks.ts`.
|
|
4
|
+
*
|
|
5
|
+
* These are CALIBRATION artifacts, not exemplar answers: their whole job is to
|
|
6
|
+
* prove this adapter's accept direction fires. Every one has been run through
|
|
7
|
+
* `createMcadCqAdapter().judge()` on this host, and a task is reported calibrated
|
|
8
|
+
* only when its gold below scores 1.0 — including the `stepEmitted` check, so
|
|
9
|
+
* every gold really does write a STEP file, which is the deviation v1 could not
|
|
10
|
+
* close.
|
|
11
|
+
*
|
|
12
|
+
* They are written plain and share one preamble of four helpers. Two of those
|
|
13
|
+
* helpers are not stylistic:
|
|
14
|
+
* - `fuse_all` runs ONE multi-argument boolean instead of N sequential unions
|
|
15
|
+
* on a growing solid. OCC's cost is superlinear in the accumulated face
|
|
16
|
+
* count, and the fin stack (task 07), the staircase (task 09) and the blade
|
|
17
|
+
* ring (task 08) all miss the judge's 120 s deadline the sequential way.
|
|
18
|
+
* - `group` builds a compound of DISJOINT cutters, so a four-bore cut is one
|
|
19
|
+
* boolean rather than four.
|
|
20
|
+
*
|
|
21
|
+
* Where a gold deviates from the prompt's literal dimensions the deviation is
|
|
22
|
+
* named in a comment at the point of the deviation, with the reason. There is one,
|
|
23
|
+
* inherited verbatim from v1: task 10's ring tooth-tip diameter.
|
|
24
|
+
*/
|
|
25
|
+
/** Imports plus the four helpers every gold below uses. */
|
|
26
|
+
const PREAMBLE = `
|
|
27
|
+
import math
|
|
28
|
+
import cadquery as cq
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def shape(s):
|
|
32
|
+
"""Unwrap a Workplane to the Shape it holds; pass Shapes through unchanged."""
|
|
33
|
+
return s.val() if isinstance(s, cq.Workplane) else s
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def rod(d, length, base, direction):
|
|
37
|
+
"""Cylinder of diameter d, \`length\` long, from \`base\` along \`direction\`."""
|
|
38
|
+
return cq.Solid.makeCylinder(d / 2.0, length, cq.Vector(*base), cq.Vector(*direction))
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def polar(r, deg):
|
|
42
|
+
"""(x, y) at radius r and angle deg, counter-clockwise from +X."""
|
|
43
|
+
a = math.radians(deg)
|
|
44
|
+
return (r * math.cos(a), r * math.sin(a))
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def group(shapes):
|
|
48
|
+
"""Disjoint shapes as one compound: no boolean, so no OCC cost."""
|
|
49
|
+
return cq.Compound.makeCompound([shape(s) for s in shapes])
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def fuse_all(parts):
|
|
53
|
+
"""ONE multi-argument boolean instead of N unions on a growing solid."""
|
|
54
|
+
xs = [shape(p) for p in parts]
|
|
55
|
+
return xs[0] if len(xs) == 1 else xs[0].fuse(*xs[1:])
|
|
56
|
+
`.trim();
|
|
57
|
+
/** The two export lines the prompt pins, verbatim. */
|
|
58
|
+
const EXPORT = `
|
|
59
|
+
cq.exporters.export(result, "part.step")
|
|
60
|
+
cq.exporters.export(result, "part.stl", exportType="STL", opt={"ascii": True}, tolerance=0.01, angularTolerance=0.05)
|
|
61
|
+
`.trim();
|
|
62
|
+
const BODIES = {
|
|
63
|
+
"calibration-block": `
|
|
64
|
+
# Chamfer BEFORE the bores: ">Z" selects the four top edges of the raw box, and
|
|
65
|
+
# doing it first means the bore walls stay square, as the prompt requires.
|
|
66
|
+
block = cq.Workplane("XY").box(100, 60, 20, centered=(True, True, False)).edges(">Z").chamfer(2)
|
|
67
|
+
bores = group([rod(8, 22, (x, y, -1), (0, 0, 1)) for x in (-35, 35) for y in (-20, 20)])
|
|
68
|
+
result = shape(block.cut(bores))
|
|
69
|
+
`.trim(),
|
|
70
|
+
"circular-flange": `
|
|
71
|
+
# "%CIRCLE" is the two outside circular edges; the extruded cylinder's third edge
|
|
72
|
+
# is its vertical seam LINE, which cannot be filleted.
|
|
73
|
+
flange = cq.Workplane("XY").circle(40).extrude(10).edges("%CIRCLE").fillet(1.5)
|
|
74
|
+
cuts = [rod(30, 12, (0, 0, -1), (0, 0, 1))]
|
|
75
|
+
cuts += [rod(6, 12, polar(30, 60 * i) + (-1,), (0, 0, 1)) for i in range(6)]
|
|
76
|
+
result = shape(flange.cut(group(cuts)))
|
|
77
|
+
`.trim(),
|
|
78
|
+
"l-bracket": `
|
|
79
|
+
# Base holes are cut into the base ALONE, before the gussets arrive. The gussets
|
|
80
|
+
# stand on the base top at X = +/-20 (16..24) and the bores sit at X = +/-25
|
|
81
|
+
# (22..28), so cutting after the union would notch a gusset; cutting first leaves
|
|
82
|
+
# the removed volume exactly pi * 3^2 * 8 per bore.
|
|
83
|
+
base = cq.Workplane("XY").box(80, 50, 8, centered=(True, True, False))
|
|
84
|
+
base = base.cut(group([rod(6, 10, (x, -10, -1), (0, 0, 1)) for x in (-25, 25)]))
|
|
85
|
+
|
|
86
|
+
# Back plate hugs the rear edge: 8 mm thick in Y at Y = 17..25, rising 50 mm from
|
|
87
|
+
# the base top (Z = 8..58).
|
|
88
|
+
back = cq.Workplane("XY").box(80, 8, 50, centered=(True, True, False)).translate((0, 21, 8))
|
|
89
|
+
|
|
90
|
+
# Gussets: right triangle 30 tall x 30 deep in the (Y, Z) plane, 8 mm thick in X.
|
|
91
|
+
# Workplane("YZ") has local x = global Y, local y = global Z, normal = +X, so the
|
|
92
|
+
# origin sits at the gusset's -X face and extrude(8) spans its thickness.
|
|
93
|
+
gussets = [
|
|
94
|
+
cq.Workplane("YZ", origin=(x - 4, 0, 0)).polyline([(17, 8), (-13, 8), (17, 38)]).close().extrude(8)
|
|
95
|
+
for x in (-20, 20)
|
|
96
|
+
]
|
|
97
|
+
|
|
98
|
+
part = cq.Workplane(obj=fuse_all([base, back] + gussets)).clean()
|
|
99
|
+
# The one outside corner of the L: the X-running edge at the rear face (max Y),
|
|
100
|
+
# lowest Z. Every other max-Y edge is higher, so the pair is unique.
|
|
101
|
+
part = part.edges(">Y and <Z").fillet(2)
|
|
102
|
+
result = shape(part.cut(group([rod(6, 12, (x, 15, 30), (0, 1, 0)) for x in (-25, 25)])))
|
|
103
|
+
`.trim(),
|
|
104
|
+
"stepped-shaft-keyway": `
|
|
105
|
+
shaft = cq.Workplane(obj=fuse_all([
|
|
106
|
+
rod(20, 30, (0, 0, 0), (1, 0, 0)),
|
|
107
|
+
rod(30, 60, (30, 0, 0), (1, 0, 0)),
|
|
108
|
+
rod(20, 30, (90, 0, 0), (1, 0, 0)),
|
|
109
|
+
])).clean()
|
|
110
|
+
# Only the two end circles have an extreme X centre; the step circles sit at
|
|
111
|
+
# X = 30 / 90 and the seam lines at the mid-point of their own segment.
|
|
112
|
+
shaft = shaft.edges("<X or >X").chamfer(1)
|
|
113
|
+
# Keyway: 6 mm wide in Y, 3 mm deep from the Z = 15 top, running X = 40..80.
|
|
114
|
+
keyway = cq.Workplane("XY").box(40, 6, 5, centered=(False, True, False)).translate((40, 0, 12))
|
|
115
|
+
result = shape(shaft.cut(keyway))
|
|
116
|
+
`.trim(),
|
|
117
|
+
"open-top-electronics-enclosure": `
|
|
118
|
+
outer = cq.Workplane("XY").box(100, 70, 30, centered=(True, True, False)).edges("|Z").fillet(2)
|
|
119
|
+
# Cavity: 3 mm walls, 3 mm floor, open at the top (the cutter runs past Z = 30).
|
|
120
|
+
cavity = cq.Workplane("XY").box(94, 64, 31, centered=(True, True, False)).translate((0, 0, 3))
|
|
121
|
+
shell = outer.cut(cavity)
|
|
122
|
+
|
|
123
|
+
# Standoffs rise from the inside floor (Z = 3) 12 mm to Z = 15; each blind hole is
|
|
124
|
+
# 3 mm across and 8 mm deep measured down from that top.
|
|
125
|
+
posts = [
|
|
126
|
+
rod(10, 12, (x, y, 3), (0, 0, 1)).cut(rod(3, 8, (x, y, 7), (0, 0, 1)))
|
|
127
|
+
for x in (-35, 35)
|
|
128
|
+
for y in (-25, 25)
|
|
129
|
+
]
|
|
130
|
+
result = shape(shell.union(group(posts)))
|
|
131
|
+
`.trim(),
|
|
132
|
+
"clevis-bracket-lightening-cutouts": `
|
|
133
|
+
base = cq.Workplane("XY").box(120, 60, 10, centered=(True, True, False)).edges("|Z").fillet(3)
|
|
134
|
+
|
|
135
|
+
# Each lug is an (X, Z) side profile 18 mm thick in Y. Workplane("XZ") has local
|
|
136
|
+
# x = global X, local y = global Z and normal = -Y, so an origin at the lug's
|
|
137
|
+
# +Y face plus extrude(18) lands on 8..26 / -26..-8, i.e. the stated 16 mm gap.
|
|
138
|
+
# Straight part Z = 10..34, semicircular cap r = 18 about Z = 34 -> top at Z = 52,
|
|
139
|
+
# exactly 42 mm above the base as the prompt states.
|
|
140
|
+
bodies = [base]
|
|
141
|
+
for y_face in (26, -8):
|
|
142
|
+
bodies.append(
|
|
143
|
+
cq.Workplane("XZ", origin=(0, y_face, 0)).moveTo(0, 10).rect(36, 24, centered=(True, False)).extrude(18)
|
|
144
|
+
)
|
|
145
|
+
bodies.append(rod(36, 18, (0, y_face, 34), (0, -1, 0)))
|
|
146
|
+
# Diagonal reinforcing ribs, 6 mm thick in Y, lying against each lug's outer face.
|
|
147
|
+
for y_face in (26, -20):
|
|
148
|
+
bodies.append(
|
|
149
|
+
cq.Workplane("XZ", origin=(0, y_face, 0)).polyline([(18, 10), (40, 10), (18, 34)]).close().extrude(6)
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
part = cq.Workplane(obj=fuse_all(bodies)).clean()
|
|
153
|
+
# 2 mm fillets at the lug/rib-to-base transitions. Filleting BEFORE the cuts keeps
|
|
154
|
+
# the selector honest: the only edges left in this box are the lug and rib feet
|
|
155
|
+
# (the base perimeter is at |X| = 60 / |Y| = 30, outside it).
|
|
156
|
+
part = part.edges(cq.selectors.BoxSelector((-42, -29, 9.5), (42, 29, 10.5))).fillet(2)
|
|
157
|
+
|
|
158
|
+
cuts = [rod(14, 60, (0, -30, 34), (0, 1, 0))]
|
|
159
|
+
cuts += [rod(7, 12, (x, y, -1), (0, 0, 1)) for x in (-45, 45) for y in (-20, 20)]
|
|
160
|
+
# Triangular lightening cutouts through the base web, corners rounded 3 mm.
|
|
161
|
+
cuts += [
|
|
162
|
+
cq.Workplane("XY", origin=(sx * 31, 0, -1))
|
|
163
|
+
.polyline([(6, 0), (-3, 5.2), (-3, -5.2)])
|
|
164
|
+
.close()
|
|
165
|
+
.offset2D(3)
|
|
166
|
+
.extrude(12)
|
|
167
|
+
for sx in (-1, 1)
|
|
168
|
+
]
|
|
169
|
+
result = shape(part.cut(group(cuts)))
|
|
170
|
+
`.trim(),
|
|
171
|
+
"radial-engine-cylinder": `
|
|
172
|
+
# One cooling fin is a 2 mm disc of radius 30 plus a torus of tube radius 1 riding
|
|
173
|
+
# its rim, so the fin outside diameter is 2 * (30 + 1) = 62 mm with the stated
|
|
174
|
+
# 1 mm round already on the outer edge. Filleting a 2 mm disc by 1 mm instead
|
|
175
|
+
# would need both fillets to meet tangentially at mid-height.
|
|
176
|
+
parts = [rod(36, 70, (0, 0, 0), (0, 0, 1))]
|
|
177
|
+
for i in range(12):
|
|
178
|
+
z = 10 + 5 * i
|
|
179
|
+
parts.append(rod(60, 2, (0, 0, z), (0, 0, 1)))
|
|
180
|
+
parts.append(cq.Solid.makeTorus(30, 1, cq.Vector(0, 0, z + 1), cq.Vector(0, 0, 1)))
|
|
181
|
+
|
|
182
|
+
# Base flange OD 70 x 8 with 1 mm rounds on both outer circular edges: the round
|
|
183
|
+
# eats inward, so the maximum radius stays exactly 35.
|
|
184
|
+
parts.append(cq.Workplane("XY").circle(35).extrude(8).edges("%CIRCLE").fillet(1))
|
|
185
|
+
parts.append(rod(44, 8, (0, 0, 70), (0, 0, 1)))
|
|
186
|
+
|
|
187
|
+
# Spark-plug boss: 12 mm dia, 24 mm long, 35 degrees above horizontal, pointing
|
|
188
|
+
# +X, rooted inside the top cap so it fuses with it.
|
|
189
|
+
boss_dir = (math.cos(math.radians(35)), 0.0, math.sin(math.radians(35)))
|
|
190
|
+
parts.append(rod(12, 24, (10, 0, 72), boss_dir))
|
|
191
|
+
|
|
192
|
+
cuts = [rod(5, 10, polar(28, 60 * i) + (-1,), (0, 0, 1)) for i in range(6)]
|
|
193
|
+
cuts.append(rod(5, 25, (10, 0, 72), boss_dir))
|
|
194
|
+
result = fuse_all(parts).cut(group(cuts))
|
|
195
|
+
`.trim(),
|
|
196
|
+
"centrifugal-impeller": `
|
|
197
|
+
# Blade centreline: radius 18 -> 43 while sweeping 45 degrees backward (clockwise
|
|
198
|
+
# seen from above, so the tips lean against counter-clockwise rotation). The
|
|
199
|
+
# outline is that centreline offset +/-1.5 mm along its own normal, so the blade
|
|
200
|
+
# is 3 mm thick everywhere and the ends are flat caps.
|
|
201
|
+
BLADE_HALF = 1.5
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
def blade_outline(steps=32):
|
|
205
|
+
dr = 25.0
|
|
206
|
+
dth = math.radians(-45.0)
|
|
207
|
+
left, right = [], []
|
|
208
|
+
for i in range(steps + 1):
|
|
209
|
+
t = i / float(steps)
|
|
210
|
+
r = 18.0 + dr * t
|
|
211
|
+
th = dth * t
|
|
212
|
+
c, s = math.cos(th), math.sin(th)
|
|
213
|
+
px, py = r * c, r * s
|
|
214
|
+
dx = dr * c - r * dth * s
|
|
215
|
+
dy = dr * s + r * dth * c
|
|
216
|
+
n = math.hypot(dx, dy)
|
|
217
|
+
nx, ny = -dy / n, dx / n
|
|
218
|
+
left.append((px + BLADE_HALF * nx, py + BLADE_HALF * ny))
|
|
219
|
+
right.append((px - BLADE_HALF * nx, py - BLADE_HALF * ny))
|
|
220
|
+
return left + right[::-1]
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
blade = cq.Workplane("XY", origin=(0, 0, 6)).polyline(blade_outline()).close().extrude(16).val()
|
|
224
|
+
|
|
225
|
+
# Backplate OD 90 x 6 with 1.5 mm rounds on both outer circular edges, then the
|
|
226
|
+
# hub. The prompt's own radii leave a 5 mm gap between the blade roots (r = 18)
|
|
227
|
+
# and the hub (r = 13), so the stated blade-to-hub root fillet has nothing to
|
|
228
|
+
# fillet and is omitted; the blades still fuse to the backplate they stand on.
|
|
229
|
+
parts = [
|
|
230
|
+
cq.Workplane("XY").circle(45).extrude(6).edges("%CIRCLE").fillet(1.5),
|
|
231
|
+
rod(26, 22, (0, 0, 6), (0, 0, 1)),
|
|
232
|
+
]
|
|
233
|
+
parts += [blade.rotate((0, 0, 0), (0, 0, 1), 30 * i) for i in range(12)]
|
|
234
|
+
result = fuse_all(parts).cut(rod(8, 30, (0, 0, -1), (0, 0, 1)))
|
|
235
|
+
`.trim(),
|
|
236
|
+
"spiral-staircase": `
|
|
237
|
+
N = 20
|
|
238
|
+
Z0 = 4.0 # first tread bottom
|
|
239
|
+
RISE = 6.0 # Z step per tread
|
|
240
|
+
TURN = 18.0 # degrees per tread
|
|
241
|
+
RAIL_R = 66.0
|
|
242
|
+
RAIL_Z0 = 14.0
|
|
243
|
+
RAIL_Z1 = 130.0
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
def rail_z(deg):
|
|
247
|
+
"""Handrail centreline height at a plan angle, counter-clockwise from +X."""
|
|
248
|
+
return RAIL_Z0 + (RAIL_Z1 - RAIL_Z0) * deg / 360.0
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
def tread(a0, z, ri=10.0, ro=62.0, ang=24.0, h=4.0, m=24):
|
|
252
|
+
pts = [polar(ri, a0 + ang * i / m) for i in range(m + 1)]
|
|
253
|
+
pts += [polar(ro, a0 + ang * (m - i) / m) for i in range(m + 1)]
|
|
254
|
+
return cq.Workplane("XY", origin=(0, 0, z)).polyline(pts).close().extrude(h)
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
parts = [
|
|
258
|
+
rod(14, 140, (0, 0, 0), (0, 0, 1)), # central column
|
|
259
|
+
rod(90, 5, (0, 0, 0), (0, 0, 1)), # base disk, Z = 0..5, catches tread 1
|
|
260
|
+
]
|
|
261
|
+
for k in range(N):
|
|
262
|
+
a0 = TURN * k
|
|
263
|
+
z0 = Z0 + RISE * k
|
|
264
|
+
parts.append(tread(a0, z0))
|
|
265
|
+
# Baluster at the tread's outer end, mid-width, rising to the handrail centre.
|
|
266
|
+
a_b = a0 + 12.0
|
|
267
|
+
parts.append(rod(3, rail_z(a_b) - z0, polar(63, a_b) + (z0,), (0, 0, 1)))
|
|
268
|
+
|
|
269
|
+
# Helical handrail: a 5 mm circle swept along one counter-clockwise turn at
|
|
270
|
+
# radius 66, rising Z = 14 -> 130.
|
|
271
|
+
path = cq.Workplane("XY").add(cq.Wire.makeHelix(RAIL_Z1 - RAIL_Z0, RAIL_Z1 - RAIL_Z0, RAIL_R, cq.Vector(0, 0, RAIL_Z0)))
|
|
272
|
+
parts.append(cq.Workplane("XZ", origin=(0, 0, RAIL_Z0)).center(RAIL_R, 0).circle(2.5).sweep(path, isFrenet=True))
|
|
273
|
+
|
|
274
|
+
result = fuse_all(parts)
|
|
275
|
+
`.trim(),
|
|
276
|
+
"planetary-gear-stage": `
|
|
277
|
+
GZ = 16.0 # gear underside; the pins (Z = 0..14) stop 2 mm short of it
|
|
278
|
+
GT = 8.0 # gear thickness
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
def gear_polygon(n, r_root, r_tip, ha_root, ha_tip, phase, arc_steps=4):
|
|
282
|
+
"""One closed outline for a straight-sided trapezoidal-tooth gear: each tooth
|
|
283
|
+
is four points between the root and tip circles, joined by chorded root arcs.
|
|
284
|
+
One polygon, so no boolean per tooth. Works for an external gear (r_tip >
|
|
285
|
+
r_root) and for the bore of an internal one (r_tip < r_root) unchanged."""
|
|
286
|
+
pts = []
|
|
287
|
+
step = 360.0 / n
|
|
288
|
+
for i in range(n):
|
|
289
|
+
a = phase + step * i
|
|
290
|
+
pts.append(polar(r_root, a - ha_root))
|
|
291
|
+
pts.append(polar(r_tip, a - ha_tip))
|
|
292
|
+
pts.append(polar(r_tip, a + ha_tip))
|
|
293
|
+
pts.append(polar(r_root, a + ha_root))
|
|
294
|
+
start, end = a + ha_root, a + step - ha_root
|
|
295
|
+
for s in range(1, arc_steps):
|
|
296
|
+
pts.append(polar(r_root, start + (end - start) * s / arc_steps))
|
|
297
|
+
return pts
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
def prism(points, z, thickness):
|
|
301
|
+
return cq.Workplane("XY", origin=(0, 0, z)).polyline(points).close().extrude(thickness).val()
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
# Sun: 24 teeth, root d42, OD 54, central bore d10. Phase 7.5 puts a tooth SPACE
|
|
305
|
+
# on each of the three planet directions (0 / 120 / 240 deg), the only phase where
|
|
306
|
+
# the sun tip circle clears the planet root circles at all.
|
|
307
|
+
sun = prism(gear_polygon(24, 21, 27, 4, 0.2, 7.5), GZ, GT).cut(rod(10, 10, (0, 0, GZ - 1), (0, 0, 1)))
|
|
308
|
+
|
|
309
|
+
# Three planets: 18 teeth, root d31, OD 41, centres on r = 42 every 120 degrees.
|
|
310
|
+
# Phase 0 puts a tooth on the sun side (local 180) and on the ring side (local 0).
|
|
311
|
+
planet = prism(gear_polygon(18, 15.5, 20.5, 5, 2, 0), GZ, GT).translate(cq.Vector(42, 0, 0))
|
|
312
|
+
planets = [planet.rotate((0, 0, 0), (0, 0, 1), 120 * i) for i in range(3)]
|
|
313
|
+
|
|
314
|
+
# Ring: 60 internal teeth, OD 140, internal root d126.
|
|
315
|
+
# DEVIATION (inherited verbatim from the v1 gold): internal tooth-tip diameter is
|
|
316
|
+
# 116, not the prompt's 114. At 114 the ring tooth tips sit at r = 57 while the
|
|
317
|
+
# planet ROOT circles reach 42 + 15.5 = 57.5, so every planet overlaps every ring
|
|
318
|
+
# tooth and the required nine separate bodies cannot exist at any phase or
|
|
319
|
+
# rotation. 116 restores 0.5 mm of tip clearance and leaves every other stated
|
|
320
|
+
# diameter untouched.
|
|
321
|
+
ring = cq.Workplane("XY", origin=(0, 0, GZ)).circle(70).extrude(GT).val()
|
|
322
|
+
ring = ring.cut(prism(gear_polygon(60, 63, 58, 1.5, 1.0, 3, arc_steps=2), GZ - 1, GT + 2))
|
|
323
|
+
|
|
324
|
+
carrier = rod(105, 4, (0, 0, -5), (0, 0, 1))
|
|
325
|
+
pins = [rod(6, 14, polar(42, 120 * i) + (0,), (0, 0, 1)) for i in range(3)]
|
|
326
|
+
|
|
327
|
+
result = group([sun] + planets + [ring, carrier] + pins)
|
|
328
|
+
`.trim()
|
|
329
|
+
};
|
|
330
|
+
/** Gold CadQuery script per task id — preamble, body, then the two export lines. */
|
|
331
|
+
const MCAD_CQ_GOLDS = Object.fromEntries(Object.entries(BODIES).map(([id, body]) => [id, `${PREAMBLE}\n\n${body}\n\n${EXPORT}\n`]));
|
|
332
|
+
/**
|
|
333
|
+
* Task ids whose CadQuery gold does NOT reach 1.0 through this adapter. Empty
|
|
334
|
+
* means every gold calibrates; an entry here is a promise that the spec was left
|
|
335
|
+
* alone and the gold is the thing that fell short, with the failing check named in
|
|
336
|
+
* a comment on the body above.
|
|
337
|
+
*/
|
|
338
|
+
const MCAD_CQ_UNCALIBRATED = /* @__PURE__ */ new Set();
|
|
339
|
+
//#endregion
|
|
340
|
+
export { MCAD_CQ_GOLDS, MCAD_CQ_UNCALIBRATED };
|
|
341
|
+
|
|
342
|
+
//# sourceMappingURL=mcad-cq-golds.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcad-cq-golds.js","names":[],"sources":["../../src/benchmarks/mcad-cq-golds.ts"],"sourcesContent":["/**\n * MCAD-CQ gold oracles — one Python CadQuery script per task in `mcad-tasks.ts`.\n *\n * These are CALIBRATION artifacts, not exemplar answers: their whole job is to\n * prove this adapter's accept direction fires. Every one has been run through\n * `createMcadCqAdapter().judge()` on this host, and a task is reported calibrated\n * only when its gold below scores 1.0 — including the `stepEmitted` check, so\n * every gold really does write a STEP file, which is the deviation v1 could not\n * close.\n *\n * They are written plain and share one preamble of four helpers. Two of those\n * helpers are not stylistic:\n * - `fuse_all` runs ONE multi-argument boolean instead of N sequential unions\n * on a growing solid. OCC's cost is superlinear in the accumulated face\n * count, and the fin stack (task 07), the staircase (task 09) and the blade\n * ring (task 08) all miss the judge's 120 s deadline the sequential way.\n * - `group` builds a compound of DISJOINT cutters, so a four-bore cut is one\n * boolean rather than four.\n *\n * Where a gold deviates from the prompt's literal dimensions the deviation is\n * named in a comment at the point of the deviation, with the reason. There is one,\n * inherited verbatim from v1: task 10's ring tooth-tip diameter.\n */\n\n/** Imports plus the four helpers every gold below uses. */\nconst PREAMBLE = `\nimport math\nimport cadquery as cq\n\n\ndef shape(s):\n \"\"\"Unwrap a Workplane to the Shape it holds; pass Shapes through unchanged.\"\"\"\n return s.val() if isinstance(s, cq.Workplane) else s\n\n\ndef rod(d, length, base, direction):\n \"\"\"Cylinder of diameter d, \\`length\\` long, from \\`base\\` along \\`direction\\`.\"\"\"\n return cq.Solid.makeCylinder(d / 2.0, length, cq.Vector(*base), cq.Vector(*direction))\n\n\ndef polar(r, deg):\n \"\"\"(x, y) at radius r and angle deg, counter-clockwise from +X.\"\"\"\n a = math.radians(deg)\n return (r * math.cos(a), r * math.sin(a))\n\n\ndef group(shapes):\n \"\"\"Disjoint shapes as one compound: no boolean, so no OCC cost.\"\"\"\n return cq.Compound.makeCompound([shape(s) for s in shapes])\n\n\ndef fuse_all(parts):\n \"\"\"ONE multi-argument boolean instead of N unions on a growing solid.\"\"\"\n xs = [shape(p) for p in parts]\n return xs[0] if len(xs) == 1 else xs[0].fuse(*xs[1:])\n`.trim()\n\n/** The two export lines the prompt pins, verbatim. */\nconst EXPORT = `\ncq.exporters.export(result, \"part.step\")\ncq.exporters.export(result, \"part.stl\", exportType=\"STL\", opt={\"ascii\": True}, tolerance=0.01, angularTolerance=0.05)\n`.trim()\n\n/** 01 — 100 x 60 x 20 block, four 8 mm through-holes, 2 mm top-perimeter chamfer. */\nconst CALIBRATION_BLOCK = `\n# Chamfer BEFORE the bores: \">Z\" selects the four top edges of the raw box, and\n# doing it first means the bore walls stay square, as the prompt requires.\nblock = cq.Workplane(\"XY\").box(100, 60, 20, centered=(True, True, False)).edges(\">Z\").chamfer(2)\nbores = group([rod(8, 22, (x, y, -1), (0, 0, 1)) for x in (-35, 35) for y in (-20, 20)])\nresult = shape(block.cut(bores))\n`.trim()\n\n/** 02 — OD 80 x 10 flange, 30 mm central bore, six 6 mm holes on a 60 mm bolt circle. */\nconst CIRCULAR_FLANGE = `\n# \"%CIRCLE\" is the two outside circular edges; the extruded cylinder's third edge\n# is its vertical seam LINE, which cannot be filleted.\nflange = cq.Workplane(\"XY\").circle(40).extrude(10).edges(\"%CIRCLE\").fillet(1.5)\ncuts = [rod(30, 12, (0, 0, -1), (0, 0, 1))]\ncuts += [rod(6, 12, polar(30, 60 * i) + (-1,), (0, 0, 1)) for i in range(6)]\nresult = shape(flange.cut(group(cuts)))\n`.trim()\n\n/** 03 — L bracket: 80 x 50 x 8 base, 80 x 8 x 50 back plate, 4 holes, 2 gussets. */\nconst L_BRACKET = `\n# Base holes are cut into the base ALONE, before the gussets arrive. The gussets\n# stand on the base top at X = +/-20 (16..24) and the bores sit at X = +/-25\n# (22..28), so cutting after the union would notch a gusset; cutting first leaves\n# the removed volume exactly pi * 3^2 * 8 per bore.\nbase = cq.Workplane(\"XY\").box(80, 50, 8, centered=(True, True, False))\nbase = base.cut(group([rod(6, 10, (x, -10, -1), (0, 0, 1)) for x in (-25, 25)]))\n\n# Back plate hugs the rear edge: 8 mm thick in Y at Y = 17..25, rising 50 mm from\n# the base top (Z = 8..58).\nback = cq.Workplane(\"XY\").box(80, 8, 50, centered=(True, True, False)).translate((0, 21, 8))\n\n# Gussets: right triangle 30 tall x 30 deep in the (Y, Z) plane, 8 mm thick in X.\n# Workplane(\"YZ\") has local x = global Y, local y = global Z, normal = +X, so the\n# origin sits at the gusset's -X face and extrude(8) spans its thickness.\ngussets = [\n cq.Workplane(\"YZ\", origin=(x - 4, 0, 0)).polyline([(17, 8), (-13, 8), (17, 38)]).close().extrude(8)\n for x in (-20, 20)\n]\n\npart = cq.Workplane(obj=fuse_all([base, back] + gussets)).clean()\n# The one outside corner of the L: the X-running edge at the rear face (max Y),\n# lowest Z. Every other max-Y edge is higher, so the pair is unique.\npart = part.edges(\">Y and <Z\").fillet(2)\nresult = shape(part.cut(group([rod(6, 12, (x, 15, 30), (0, 1, 0)) for x in (-25, 25)])))\n`.trim()\n\n/** 04 — stepped shaft along X with 1 mm end chamfers and a top keyway. */\nconst STEPPED_SHAFT_KEYWAY = `\nshaft = cq.Workplane(obj=fuse_all([\n rod(20, 30, (0, 0, 0), (1, 0, 0)),\n rod(30, 60, (30, 0, 0), (1, 0, 0)),\n rod(20, 30, (90, 0, 0), (1, 0, 0)),\n])).clean()\n# Only the two end circles have an extreme X centre; the step circles sit at\n# X = 30 / 90 and the seam lines at the mid-point of their own segment.\nshaft = shaft.edges(\"<X or >X\").chamfer(1)\n# Keyway: 6 mm wide in Y, 3 mm deep from the Z = 15 top, running X = 40..80.\nkeyway = cq.Workplane(\"XY\").box(40, 6, 5, centered=(False, True, False)).translate((40, 0, 12))\nresult = shape(shaft.cut(keyway))\n`.trim()\n\n/** 05 — open-top enclosure, 3 mm walls/floor, four standoffs with blind holes. */\nconst OPEN_TOP_ELECTRONICS_ENCLOSURE = `\nouter = cq.Workplane(\"XY\").box(100, 70, 30, centered=(True, True, False)).edges(\"|Z\").fillet(2)\n# Cavity: 3 mm walls, 3 mm floor, open at the top (the cutter runs past Z = 30).\ncavity = cq.Workplane(\"XY\").box(94, 64, 31, centered=(True, True, False)).translate((0, 0, 3))\nshell = outer.cut(cavity)\n\n# Standoffs rise from the inside floor (Z = 3) 12 mm to Z = 15; each blind hole is\n# 3 mm across and 8 mm deep measured down from that top.\nposts = [\n rod(10, 12, (x, y, 3), (0, 0, 1)).cut(rod(3, 8, (x, y, 7), (0, 0, 1)))\n for x in (-35, 35)\n for y in (-25, 25)\n]\nresult = shape(shell.union(group(posts)))\n`.trim()\n\n/** 06 — clevis bracket: base plate, two lugs with a 14 mm pin bore, ribs, cutouts. */\nconst CLEVIS_BRACKET = `\nbase = cq.Workplane(\"XY\").box(120, 60, 10, centered=(True, True, False)).edges(\"|Z\").fillet(3)\n\n# Each lug is an (X, Z) side profile 18 mm thick in Y. Workplane(\"XZ\") has local\n# x = global X, local y = global Z and normal = -Y, so an origin at the lug's\n# +Y face plus extrude(18) lands on 8..26 / -26..-8, i.e. the stated 16 mm gap.\n# Straight part Z = 10..34, semicircular cap r = 18 about Z = 34 -> top at Z = 52,\n# exactly 42 mm above the base as the prompt states.\nbodies = [base]\nfor y_face in (26, -8):\n bodies.append(\n cq.Workplane(\"XZ\", origin=(0, y_face, 0)).moveTo(0, 10).rect(36, 24, centered=(True, False)).extrude(18)\n )\n bodies.append(rod(36, 18, (0, y_face, 34), (0, -1, 0)))\n# Diagonal reinforcing ribs, 6 mm thick in Y, lying against each lug's outer face.\nfor y_face in (26, -20):\n bodies.append(\n cq.Workplane(\"XZ\", origin=(0, y_face, 0)).polyline([(18, 10), (40, 10), (18, 34)]).close().extrude(6)\n )\n\npart = cq.Workplane(obj=fuse_all(bodies)).clean()\n# 2 mm fillets at the lug/rib-to-base transitions. Filleting BEFORE the cuts keeps\n# the selector honest: the only edges left in this box are the lug and rib feet\n# (the base perimeter is at |X| = 60 / |Y| = 30, outside it).\npart = part.edges(cq.selectors.BoxSelector((-42, -29, 9.5), (42, 29, 10.5))).fillet(2)\n\ncuts = [rod(14, 60, (0, -30, 34), (0, 1, 0))]\ncuts += [rod(7, 12, (x, y, -1), (0, 0, 1)) for x in (-45, 45) for y in (-20, 20)]\n# Triangular lightening cutouts through the base web, corners rounded 3 mm.\ncuts += [\n cq.Workplane(\"XY\", origin=(sx * 31, 0, -1))\n .polyline([(6, 0), (-3, 5.2), (-3, -5.2)])\n .close()\n .offset2D(3)\n .extrude(12)\n for sx in (-1, 1)\n]\nresult = shape(part.cut(group(cuts)))\n`.trim()\n\n/** 07 — radial engine cylinder: barrel, 12 fins, base flange, top cap, plug boss. */\nconst RADIAL_ENGINE_CYLINDER = `\n# One cooling fin is a 2 mm disc of radius 30 plus a torus of tube radius 1 riding\n# its rim, so the fin outside diameter is 2 * (30 + 1) = 62 mm with the stated\n# 1 mm round already on the outer edge. Filleting a 2 mm disc by 1 mm instead\n# would need both fillets to meet tangentially at mid-height.\nparts = [rod(36, 70, (0, 0, 0), (0, 0, 1))]\nfor i in range(12):\n z = 10 + 5 * i\n parts.append(rod(60, 2, (0, 0, z), (0, 0, 1)))\n parts.append(cq.Solid.makeTorus(30, 1, cq.Vector(0, 0, z + 1), cq.Vector(0, 0, 1)))\n\n# Base flange OD 70 x 8 with 1 mm rounds on both outer circular edges: the round\n# eats inward, so the maximum radius stays exactly 35.\nparts.append(cq.Workplane(\"XY\").circle(35).extrude(8).edges(\"%CIRCLE\").fillet(1))\nparts.append(rod(44, 8, (0, 0, 70), (0, 0, 1)))\n\n# Spark-plug boss: 12 mm dia, 24 mm long, 35 degrees above horizontal, pointing\n# +X, rooted inside the top cap so it fuses with it.\nboss_dir = (math.cos(math.radians(35)), 0.0, math.sin(math.radians(35)))\nparts.append(rod(12, 24, (10, 0, 72), boss_dir))\n\ncuts = [rod(5, 10, polar(28, 60 * i) + (-1,), (0, 0, 1)) for i in range(6)]\ncuts.append(rod(5, 25, (10, 0, 72), boss_dir))\nresult = fuse_all(parts).cut(group(cuts))\n`.trim()\n\n/** 08 — centrifugal impeller: backplate, hub, 12 backward-curved blades, bore. */\nconst CENTRIFUGAL_IMPELLER = `\n# Blade centreline: radius 18 -> 43 while sweeping 45 degrees backward (clockwise\n# seen from above, so the tips lean against counter-clockwise rotation). The\n# outline is that centreline offset +/-1.5 mm along its own normal, so the blade\n# is 3 mm thick everywhere and the ends are flat caps.\nBLADE_HALF = 1.5\n\n\ndef blade_outline(steps=32):\n dr = 25.0\n dth = math.radians(-45.0)\n left, right = [], []\n for i in range(steps + 1):\n t = i / float(steps)\n r = 18.0 + dr * t\n th = dth * t\n c, s = math.cos(th), math.sin(th)\n px, py = r * c, r * s\n dx = dr * c - r * dth * s\n dy = dr * s + r * dth * c\n n = math.hypot(dx, dy)\n nx, ny = -dy / n, dx / n\n left.append((px + BLADE_HALF * nx, py + BLADE_HALF * ny))\n right.append((px - BLADE_HALF * nx, py - BLADE_HALF * ny))\n return left + right[::-1]\n\n\nblade = cq.Workplane(\"XY\", origin=(0, 0, 6)).polyline(blade_outline()).close().extrude(16).val()\n\n# Backplate OD 90 x 6 with 1.5 mm rounds on both outer circular edges, then the\n# hub. The prompt's own radii leave a 5 mm gap between the blade roots (r = 18)\n# and the hub (r = 13), so the stated blade-to-hub root fillet has nothing to\n# fillet and is omitted; the blades still fuse to the backplate they stand on.\nparts = [\n cq.Workplane(\"XY\").circle(45).extrude(6).edges(\"%CIRCLE\").fillet(1.5),\n rod(26, 22, (0, 0, 6), (0, 0, 1)),\n]\nparts += [blade.rotate((0, 0, 0), (0, 0, 1), 30 * i) for i in range(12)]\nresult = fuse_all(parts).cut(rod(8, 30, (0, 0, -1), (0, 0, 1)))\n`.trim()\n\n/** 09 — spiral staircase: column, 20 helical treads, helical handrail, balusters. */\nconst SPIRAL_STAIRCASE = `\nN = 20\nZ0 = 4.0 # first tread bottom\nRISE = 6.0 # Z step per tread\nTURN = 18.0 # degrees per tread\nRAIL_R = 66.0\nRAIL_Z0 = 14.0\nRAIL_Z1 = 130.0\n\n\ndef rail_z(deg):\n \"\"\"Handrail centreline height at a plan angle, counter-clockwise from +X.\"\"\"\n return RAIL_Z0 + (RAIL_Z1 - RAIL_Z0) * deg / 360.0\n\n\ndef tread(a0, z, ri=10.0, ro=62.0, ang=24.0, h=4.0, m=24):\n pts = [polar(ri, a0 + ang * i / m) for i in range(m + 1)]\n pts += [polar(ro, a0 + ang * (m - i) / m) for i in range(m + 1)]\n return cq.Workplane(\"XY\", origin=(0, 0, z)).polyline(pts).close().extrude(h)\n\n\nparts = [\n rod(14, 140, (0, 0, 0), (0, 0, 1)), # central column\n rod(90, 5, (0, 0, 0), (0, 0, 1)), # base disk, Z = 0..5, catches tread 1\n]\nfor k in range(N):\n a0 = TURN * k\n z0 = Z0 + RISE * k\n parts.append(tread(a0, z0))\n # Baluster at the tread's outer end, mid-width, rising to the handrail centre.\n a_b = a0 + 12.0\n parts.append(rod(3, rail_z(a_b) - z0, polar(63, a_b) + (z0,), (0, 0, 1)))\n\n# Helical handrail: a 5 mm circle swept along one counter-clockwise turn at\n# radius 66, rising Z = 14 -> 130.\npath = cq.Workplane(\"XY\").add(cq.Wire.makeHelix(RAIL_Z1 - RAIL_Z0, RAIL_Z1 - RAIL_Z0, RAIL_R, cq.Vector(0, 0, RAIL_Z0)))\nparts.append(cq.Workplane(\"XZ\", origin=(0, 0, RAIL_Z0)).center(RAIL_R, 0).circle(2.5).sweep(path, isFrenet=True))\n\nresult = fuse_all(parts)\n`.trim()\n\n/** 10 — planetary gear stage: 9 separate bodies (sun, 3 planets, ring, carrier, 3 pins). */\nconst PLANETARY_GEAR_STAGE = `\nGZ = 16.0 # gear underside; the pins (Z = 0..14) stop 2 mm short of it\nGT = 8.0 # gear thickness\n\n\ndef gear_polygon(n, r_root, r_tip, ha_root, ha_tip, phase, arc_steps=4):\n \"\"\"One closed outline for a straight-sided trapezoidal-tooth gear: each tooth\n is four points between the root and tip circles, joined by chorded root arcs.\n One polygon, so no boolean per tooth. Works for an external gear (r_tip >\n r_root) and for the bore of an internal one (r_tip < r_root) unchanged.\"\"\"\n pts = []\n step = 360.0 / n\n for i in range(n):\n a = phase + step * i\n pts.append(polar(r_root, a - ha_root))\n pts.append(polar(r_tip, a - ha_tip))\n pts.append(polar(r_tip, a + ha_tip))\n pts.append(polar(r_root, a + ha_root))\n start, end = a + ha_root, a + step - ha_root\n for s in range(1, arc_steps):\n pts.append(polar(r_root, start + (end - start) * s / arc_steps))\n return pts\n\n\ndef prism(points, z, thickness):\n return cq.Workplane(\"XY\", origin=(0, 0, z)).polyline(points).close().extrude(thickness).val()\n\n\n# Sun: 24 teeth, root d42, OD 54, central bore d10. Phase 7.5 puts a tooth SPACE\n# on each of the three planet directions (0 / 120 / 240 deg), the only phase where\n# the sun tip circle clears the planet root circles at all.\nsun = prism(gear_polygon(24, 21, 27, 4, 0.2, 7.5), GZ, GT).cut(rod(10, 10, (0, 0, GZ - 1), (0, 0, 1)))\n\n# Three planets: 18 teeth, root d31, OD 41, centres on r = 42 every 120 degrees.\n# Phase 0 puts a tooth on the sun side (local 180) and on the ring side (local 0).\nplanet = prism(gear_polygon(18, 15.5, 20.5, 5, 2, 0), GZ, GT).translate(cq.Vector(42, 0, 0))\nplanets = [planet.rotate((0, 0, 0), (0, 0, 1), 120 * i) for i in range(3)]\n\n# Ring: 60 internal teeth, OD 140, internal root d126.\n# DEVIATION (inherited verbatim from the v1 gold): internal tooth-tip diameter is\n# 116, not the prompt's 114. At 114 the ring tooth tips sit at r = 57 while the\n# planet ROOT circles reach 42 + 15.5 = 57.5, so every planet overlaps every ring\n# tooth and the required nine separate bodies cannot exist at any phase or\n# rotation. 116 restores 0.5 mm of tip clearance and leaves every other stated\n# diameter untouched.\nring = cq.Workplane(\"XY\", origin=(0, 0, GZ)).circle(70).extrude(GT).val()\nring = ring.cut(prism(gear_polygon(60, 63, 58, 1.5, 1.0, 3, arc_steps=2), GZ - 1, GT + 2))\n\ncarrier = rod(105, 4, (0, 0, -5), (0, 0, 1))\npins = [rod(6, 14, polar(42, 120 * i) + (0,), (0, 0, 1)) for i in range(3)]\n\nresult = group([sun] + planets + [ring, carrier] + pins)\n`.trim()\n\nconst BODIES: Record<string, string> = {\n 'calibration-block': CALIBRATION_BLOCK,\n 'circular-flange': CIRCULAR_FLANGE,\n 'l-bracket': L_BRACKET,\n 'stepped-shaft-keyway': STEPPED_SHAFT_KEYWAY,\n 'open-top-electronics-enclosure': OPEN_TOP_ELECTRONICS_ENCLOSURE,\n 'clevis-bracket-lightening-cutouts': CLEVIS_BRACKET,\n 'radial-engine-cylinder': RADIAL_ENGINE_CYLINDER,\n 'centrifugal-impeller': CENTRIFUGAL_IMPELLER,\n 'spiral-staircase': SPIRAL_STAIRCASE,\n 'planetary-gear-stage': PLANETARY_GEAR_STAGE,\n}\n\n/** Gold CadQuery script per task id — preamble, body, then the two export lines. */\nexport const MCAD_CQ_GOLDS: Record<string, string> = Object.fromEntries(\n Object.entries(BODIES).map(([id, body]) => [id, `${PREAMBLE}\\n\\n${body}\\n\\n${EXPORT}\\n`]),\n)\n\n/**\n * Task ids whose CadQuery gold does NOT reach 1.0 through this adapter. Empty\n * means every gold calibrates; an entry here is a promise that the spec was left\n * alone and the gold is the thing that fell short, with the failing check named in\n * a comment on the body above.\n */\nexport const MCAD_CQ_UNCALIBRATED: ReadonlySet<string> = new Set<string>()\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAyBA,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA8Bf,KAAK;;AAGP,MAAM,SAAS;;;EAGb,KAAK;AAgSP,MAAM,SAAiC;CACrC,qBA9RwB;;;;;;EAMxB,KAwRqC;CACrC,mBAtRsB;;;;;;;EAOtB,KA+QiC;CACjC,aA7QgB;;;;;;;;;;;;;;;;;;;;;;;;;EAyBhB,KAoPqB;CACrB,wBAlP2B;;;;;;;;;;;;EAY3B,KAsO2C;CAC3C,kCApOqC;;;;;;;;;;;;;;EAcrC,KAsN+D;CAC/D,qCApNqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAsCrB,KA8KkD;CAClD,0BA5K6B;;;;;;;;;;;;;;;;;;;;;;;;EAwB7B,KAoJ+C;CAC/C,wBAlJ2B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAuC3B,KA2G2C;CAC3C,oBAzGuB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAuCvB,KAkEmC;CACnC,wBAhE2B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAoD3B,KAY2C;AAC7C;;AAGA,MAAa,gBAAwC,OAAO,YAC1D,OAAO,QAAQ,MAAM,CAAC,CAAC,KAAK,CAAC,IAAI,UAAU,CAAC,IAAI,GAAG,SAAS,MAAM,KAAK,MAAM,OAAO,GAAG,CAAC,CAC1F;;;;;;;AAQA,MAAa,uCAA4C,IAAI,IAAY"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
//#region src/benchmarks/mcad-golds.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* MCAD gold oracles — one OpenSCAD model per task in `mcad-tasks.ts`.
|
|
4
|
+
*
|
|
5
|
+
* These are CALIBRATION artifacts, not exemplar answers: their whole job is to
|
|
6
|
+
* prove the judge's accept direction fires, so they are written plain (no clever
|
|
7
|
+
* parametrics, `$fn=96` on round features) and every one of them has been run
|
|
8
|
+
* through `createMcadBenchAdapter().judge()` on this host. A task is marked
|
|
9
|
+
* `calibrated: true` in `mcad-tasks.ts` only when its gold below scores 1.0.
|
|
10
|
+
*
|
|
11
|
+
* Where a gold deviates from the prompt's literal dimensions, the deviation is
|
|
12
|
+
* named in a comment at the point of the deviation, with the reason. There is one
|
|
13
|
+
* such deviation (task 10's ring tooth-tip diameter — the prompt's own numbers
|
|
14
|
+
* make a coplanar 9-body assembly geometrically impossible; see the comment).
|
|
15
|
+
*/
|
|
16
|
+
/** Gold OpenSCAD source per task id. */
|
|
17
|
+
declare const MCAD_GOLDS: Record<string, string>;
|
|
18
|
+
//#endregion
|
|
19
|
+
export { MCAD_GOLDS };
|
|
20
|
+
//# sourceMappingURL=mcad-golds.d.ts.map
|