burr 0.29.0

Design-rule checks for CAD-as-code workflows.
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
# Fray Website Burr Gallery Contract

This contract lets the Fray website render Burr gallery content without
regenerating CAD.

## Source

```txt
repo: fraylabs/burr
release_tag: burr-v0.29.0
asset_name: burr-gallery-v0.29.0.zip
asset_url: https://github.com/fraylabs/burr/releases/download/burr-v0.29.0/burr-gallery-v0.29.0.zip
```

The website should treat Burr release assets as read-only product data.

## Rules

- Burr owns CAD source, generated gallery artifacts, receipts, and manifest
  shape.
- Fray website consumes the zip and renders it.
- Fray website must not regenerate CAD.
- PNG previews are visual review artifacts only.
- Burr receipts are the proof artifacts.
- A passing gallery card should be based on receipt `status: "pass"`, not on
  image appearance.
- A failing gallery card is allowed when `expectation: "fail"` and the receipt
  has at least one failed check. These are intentional negative fixtures.
- A before/after repair proof is a pair of receipt-backed states: the before
  card fails for a declared mechanical reason, and the after card passes after
  the CAD is repaired.

## Zip Layout

```txt
burr-gallery-v0.29.0/
  README.md
  manifest.json
  repair-reports/
    actuator-housing-edge-distance.json
    actuator-housing-edge-distance.md
  shaft-bearing-bracket/
    shaft-bearing-bracket.png
    shaft-bearing-bracket.receipt.json
    shaft-bearing-bracket.design-data.json
  slotted-motor-plate/
    slotted-motor-plate.png
    slotted-motor-plate.receipt.json
    slotted-motor-plate.design-data.json
  edge-safe-bearing-seat/
    edge-safe-bearing-seat.png
    edge-safe-bearing-seat.receipt.json
    edge-safe-bearing-seat.design-data.json
  electronics-standoff-deck/
    electronics-standoff-deck.png
    electronics-standoff-deck.receipt.json
    electronics-standoff-deck.design-data.json
  dense-random-hole-plate/
    dense-random-hole-plate.png
    dense-random-hole-plate.receipt.json
    dense-random-hole-plate.design-data.json
  bad-bearing-seat-missing-shoulder/
    bad-bearing-seat-missing-shoulder.png
    bad-bearing-seat-missing-shoulder.receipt.json
    bad-bearing-seat-missing-shoulder.design-data.json
  bad-bearing-seat-near-edge/
    bad-bearing-seat-near-edge.png
    bad-bearing-seat-near-edge.receipt.json
    bad-bearing-seat-near-edge.design-data.json
  bad-counterbore-missing-recess/
    bad-counterbore-missing-recess.png
    bad-counterbore-missing-recess.receipt.json
    bad-counterbore-missing-recess.design-data.json
  bad-insert-pocket-through-hole/
    bad-insert-pocket-through-hole.png
    bad-insert-pocket-through-hole.receipt.json
    bad-insert-pocket-through-hole.design-data.json
  bad-slot-disconnected-holes/
    bad-slot-disconnected-holes.png
    bad-slot-disconnected-holes.receipt.json
    bad-slot-disconnected-holes.design-data.json
```

## Manifest

Manifest path:

```txt
burr-gallery-v0.29.0/manifest.json
```

Schema:

```json
{
  "schema_version": "burr.gallery-artifact.v1",
  "burr_version": "0.29.0",
  "artifact_id": "burr-gallery-v0.29.0",
  "generated_at": "ISO-8601 timestamp",
  "source": {
    "repository": "fraylabs/burr",
    "tag": "burr-v0.29.0"
  },
  "repair_reports": [
    {
      "id": "actuator-housing-edge-distance",
      "title": "Actuator Housing Edge-Distance Repair",
      "kind": "before_after",
      "before_slug": "bad-actuator-housing-edge-distance",
      "after_slug": "fixed-actuator-housing",
      "status": "pass",
      "report_json": "repair-reports/actuator-housing-edge-distance.json",
      "report_markdown": "repair-reports/actuator-housing-edge-distance.md"
    }
  ],
  "examples": [
    {
      "slug": "shaft-bearing-bracket",
      "title": "Shaft Bearing Bracket",
      "expectation": "pass",
      "group": "functional-good",
      "preview": "shaft-bearing-bracket/shaft-bearing-bracket.png",
      "receipt": "shaft-bearing-bracket/shaft-bearing-bracket.receipt.json",
      "design_data": "shaft-bearing-bracket/shaft-bearing-bracket.design-data.json",
      "status": "pass",
      "failed_rules": [],
      "checked_features": ["bearing_608_primary"],
      "unchecked_features": ["cosmetic_relief_recess"]
    },
    {
      "slug": "bad-counterbore-missing-recess",
      "title": "Bad Counterbore Missing Recess",
      "expectation": "fail",
      "group": "mistake-caught",
      "preview": "bad-counterbore-missing-recess/bad-counterbore-missing-recess.png",
      "receipt": "bad-counterbore-missing-recess/bad-counterbore-missing-recess.receipt.json",
      "design_data": "bad-counterbore-missing-recess/bad-counterbore-missing-recess.design-data.json",
      "status": "fail",
      "failed_rules": [
        {
          "rule_id": "actuator_mount:counterbore_step_presence",
          "feature_id": "m3_mount_counterbore",
          "reason": "missing_declared_feature",
          "message": "Declared counterbore m3_mount_counterbore is missing from the STEP artifact."
        }
      ],
      "checked_features": ["m3_mount_counterbore"],
      "unchecked_features": ["cosmetic_counterbore"]
    }
  ]
}
```

`checked_features` and `unchecked_features` are display summaries copied from
the Burr receipt. The receipt remains the source of proof if the website needs
more detail. `failed_rules` is a display summary copied from failed receipt
checks for intentional negative fixtures.

## Burr 0.14 Repair Narrative

For Burr 0.14, render the actuator repair proof as one simple loop:

```txt
bad CAD -> Burr check -> explain fix order -> fixed CAD passes
```

Use the existing manifest and receipt fields. No website-side CAD regeneration
or new geometry interpretation is required.

Recommended repair copy:

```txt
Before: Burr caught the declared actuator mistake.
Check: the receipt records the measured failure.
Fix order: burr explain says what to repair first.
After: the repaired actuator has a passing Burr receipt.
```

For the bad actuator card, use the failed receipt summary to say what Burr
caught. For the fixed actuator card, use `status: "pass"` to say the declared
actuator checks now pass. Do not imply that Burr designed the repair; Burr
checked the before state, explained the fix order, and checked the after state.

## Burr 0.16 Repair Reports

Burr 0.16 repair reports include portable `repair_actions[]` in the same gallery
artifact. A report is not a new verifier. It is a receipt-backed summary of the
before/after loop, with suggested actions derived from the bad/fixed receipts and
design data only.

Report JSON schema:

```json
{
  "schema_version": "burr.repair-report.v1",
  "id": "actuator-housing-edge-distance",
  "title": "Actuator Housing Edge-Distance Repair",
  "status": "pass",
  "loop": "bad CAD -> Burr check -> explain fix order -> fixed CAD passes",
  "first_fix": "Move the loaded M3 holes inward or increase the surrounding housing size.",
  "before": {
    "slug": "bad-actuator-housing-edge-distance",
    "status": "fail",
    "receipt": "bad-actuator-housing-edge-distance/bad-actuator-housing-edge-distance.receipt.json",
    "failures": 4
  },
  "repair_actions": [
    {
      "feature_id": "m3_front_left",
      "action": "move_feature",
      "parameter": "center_mm",
      "before_value_mm": [-28, -8, 9],
      "after_value_mm": [-22, -12, 9],
      "suggested_delta_mm": [6, -4, 0],
      "source_hint": {
        "source_file_path": "examples/build123d-actuator-housing-repair/bad/design.py",
        "edit_kind": "replace_python_dict_entry",
        "selector": "mount_holes[\"m3_front_left\"]",
        "before_text": "    \"m3_front_left\": (-28.0, -8.0, hole_z),",
        "after_text": "    \"m3_front_left\": (-22.0, -12.0, hole_z),",
        "feature_id": "m3_front_left",
        "parameter": "center_mm",
        "value_path": "features[id=m3_front_left].center_mm",
        "before_value_mm": [-28, -8, 9],
        "after_value_mm": [-22, -12, 9],
        "confidence": "exact_from_design_data",
        "rationale": "The before and after design data declare features[id=m3_front_left].center_mm; updating that editable value moves the failed clearance-hole center used by this edge-distance check."
      },
      "failure_reason": "insufficient_edge_distance",
      "reason": "Move m3_front_left from [-28, -8, 9] mm to [-22, -12, 9] mm so center-to-edge increases from 8 mm to at least 10.2 mm.",
      "measured": { "center_to_edge_mm": 8.0 },
      "required": { "center_to_edge_mm": 10.2 },
      "margin_mm": -2.2,
      "verifies_against_after_feature": {
        "feature_id": "m3_front_left",
        "status": "pass",
        "margin_mm": 1.8
      }
    }
  ],
  "after": {
    "slug": "fixed-actuator-housing",
    "status": "pass",
    "receipt": "fixed-actuator-housing/fixed-actuator-housing.receipt.json"
  }
}
```

The website should render report Markdown or selected report JSON fields only
when `manifest.repair_reports[]` declares the files. Do not infer report paths.

## Burr 0.18 Repair Action Contract V3

Burr 0.18 adds required source-text fields to `source_hint` objects in
`repair_actions[]`. Repair
actions remain machine-readable suggestions derived from the bad/fixed receipts
and design data. They are not automatic CAD edits.

Every `move_feature` repair action must map to one failed before-receipt check
by `rule_id` and `feature_id`. A supplemental action may describe a source edit
needed by the same before/after repair, such as resizing the housing envelope.
Every action includes `source_hint`, which maps the suggested edit back to
source text and design data:

- `source_file_path`: source file path for the failing before design.
- `edit_kind`: explicit edit operation, such as `replace_python_dict_entry` or
  `replace_python_assignment`.
- `selector`: stable source selector for the edit target.
- `before_text`: exact source snippet in the failing before design, occurring
  exactly once.
- `after_text`: exact source snippet in the fixed after design, occurring
  exactly once.
- `feature_id`: same feature id as the failure and action.
- `parameter`: editable value name, currently `center_mm` for actuator hole
  movement.
- `value_path`: stable design-data path to the editable value, currently
  `features[id=<feature_id>].center_mm`.
- `before_value_mm`: exact value from the bad design data.
- `after_value_mm`: exact value from the fixed design data.
- `confidence`: currently `exact_from_design_data`.
- `rationale`: short human explanation of why this source hint is the edit
  target.

Agent source-edit loop:

```txt
generate: agent writes CAD source and artifacts
  -> check: Burr check writes a receipt
  -> explain-json: Burr explain --json returns a repair packet
  -> apply only exact source_hint.before_text -> source_hint.after_text edits
  -> regenerate design data and STEP from edited source
  -> check again
  -> stop when pass, or when no exact source edit is available
```

The repair packet must be treated as a guarded edit contract. A consumer may
apply a repair action only when `source_hint.before_text` occurs exactly once in
the current source file, the `source_hint.value_path` matches the declared
before design data value, and `source_hint.confidence` is
`exact_from_design_data`. Consumers must not infer a nearby edit, rewrite CAD
from measured geometry alone, or treat the repair report as the verifier. The
verifier is the regenerated Burr receipt after the exact source edit. If the
packet has no exact source edits left, or any exact-text/value-path guard fails,
the runner must stop rather than guess.

Example action:

```json
{
  "feature_id": "m3_front_left",
  "action": "move_feature",
  "parameter": "center_mm",
  "before_value_mm": [-28, -8, 9],
  "after_value_mm": [-22, -12, 9],
  "suggested_delta_mm": [6, -4, 0],
  "source_hint": {
    "source_file_path": "examples/build123d-actuator-housing-repair/bad/design.py",
    "edit_kind": "replace_python_dict_entry",
    "selector": "mount_holes[\"m3_front_left\"]",
    "before_text": "    \"m3_front_left\": (-28.0, -8.0, hole_z),",
    "after_text": "    \"m3_front_left\": (-22.0, -12.0, hole_z),",
    "feature_id": "m3_front_left",
    "parameter": "center_mm",
    "value_path": "features[id=m3_front_left].center_mm",
    "before_value_mm": [-28, -8, 9],
    "after_value_mm": [-22, -12, 9],
    "confidence": "exact_from_design_data",
    "rationale": "The before and after design data declare features[id=m3_front_left].center_mm; updating that editable value moves the failed clearance-hole center used by this edge-distance check."
  },
  "failure_reason": "insufficient_edge_distance",
  "reason": "Move m3_front_left from [-28, -8, 9] mm to [-22, -12, 9] mm so center-to-edge increases from 8 mm to at least 10.2 mm.",
  "measured": { "center_to_edge_mm": 8.0 },
  "required": { "center_to_edge_mm": 10.2 },
  "margin_mm": -2.2,
  "verifies_against_after_feature": {
    "feature_id": "m3_front_left",
    "status": "pass",
    "margin_mm": 1.8
  }
}
```

Supplemental envelope action example:

```json
{
  "feature_id": "housing",
  "action": "resize_part_envelope",
  "parameter": "bbox_mm.size[1]",
  "before_value_mm": 34,
  "after_value_mm": 48,
  "suggested_delta_mm": 14,
  "source_hint": {
    "source_file_path": "examples/build123d-actuator-housing-repair/bad/design.py",
    "edit_kind": "replace_python_assignment",
    "selector": "housing_width",
    "before_text": "housing_width = 34.0",
    "after_text": "housing_width = 48.0",
    "feature_id": "housing",
    "parameter": "bbox_mm.size[1]",
    "value_path": "parts[id=housing].bbox_mm.size[1]",
    "before_value_mm": 34,
    "after_value_mm": 48,
    "confidence": "exact_from_design_data",
    "rationale": "The before and after design data declare parts[id=housing].bbox_mm; updating housing_width changes the housing envelope needed by the moved mounting holes."
  },
  "failure_reason": "supporting_envelope_change"
}
```

## Website Rendering

For each `examples[]` entry, render:

- `title`
- PNG at `preview`
- receipt `status`
- `expectation`
- checked feature count and names
- unchecked feature count and names
- failed rule summaries when `status: "fail"`
- optional link/download to the full receipt JSON

Recommended card copy:

```txt
Status: pass
Proof: Burr receipt
Visual: generated STEP preview
```

For an intentional negative fixture:

```txt
Status: fail
Expectation: fail
Proof: Burr caught the declared mistake
Visual: generated STEP preview
```

Do not call a preview "verified" by itself. Call the receipt verified.

## Update Policy

For a new Burr release:

1. Run `npm run check:gallery:artifact` in the Burr repo.
2. Upload `artifacts/releases/burr-gallery-v<version>.zip` to the matching
   GitHub release tag.
3. Update the website config to the new `release_tag`, `asset_name`, and
   `asset_url`.

The website data model should use:

```json
{
  "repo": "fraylabs/burr",
  "release_tag": "burr-v0.29.0",
  "asset_name": "burr-gallery-v0.29.0.zip"
}
```

This keeps the website independent of whether assets later come from GitHub
release assets, a CDN, or a checked-in `assets/` folder.