Skip to content

Commit 1380ca0

Browse files
aldoruizlunaclaude
andauthored
feat(bed-extrusion-mount): graph twin of the script (graph format 1.1) (#165)
bed-mount.graph.json is a golden twin of main.py, declared as graph_file on the bed_mount mode beside the script (owner decision D5: graph twins coexist with scripts, parity-checked; main.py stays the rendered source and the oracle). Digital Twins phase 8b, lane P8-TWINS-B. Same parameters (declared in `parameters`), same derivations (the three clamps as ternary pairs in `derived`, the constants under main.py's names and values) and the same operations in the same order: each _box is a centred box translated to its centre, each _cyl_z an XY profile_circle extruded and translated to its start. y4d-spec check --render --require-openscad --parity ./bed-extrusion-mount: 8 renders, parity 4/4 at 0.000000 mm (defaults + standard, wide_long, thin_plate), frames 32/32 ok, failures 0. Frames and presets unchanged. Assembly A validates (235/235 placed, 292/292 mates, poses 23/23, --collision partial as on main); its digest moves cb80b679... -> 1bce5e9b... because the cartridge gains a file. Signed-off-by: Aldo Ruiz Luna <aldo.ruiz.luna@gmail.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
1 parent 345bc45 commit 1380ca0

3 files changed

Lines changed: 69 additions & 0 deletions

File tree

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
{
2+
"version": "1.1.0",
3+
"units": "mm",
4+
"meta": {
5+
"title": "Bed Extrusion Mount (graph twin)",
6+
"notes": "Golden twin of main.py (graph format 1.1): the same parameters, the same derivations and the same operations in the same order. main.py stays the oracle; y4d-spec --parity compares the two at the defaults and at every preset. Constants keep main.py's names and values, and their sources are main.py's: ISO 7380-1 M5x10 (SCREW_D 5, HEAD_DK 9.5), MISUMI HFS5 2020 (SLOT_LIP_T 2, PROFILE 20), MISUMI HNTAP5-5 (TNUT_L 15); HOLE_CLEAR, TAB_W, EDGE, BED_SCREW_Y and CROSS_IN are main.py's labelled conventions. Clamps max(lo, min(x, hi)) are ternary pairs, because the expression dialect has no function calls. _box(x0..z1) is a centred box translated to its centre; _cyl_z is an XY circle extruded and translated to z0."
7+
},
8+
"parameters": {
9+
"screw_offset": {"default": 14.0},
10+
"stem_length": {"default": 17.5},
11+
"plate_t": {"default": 4.5}
12+
},
13+
"derived": [
14+
{"id": "SCREW_D", "expr": "5.0"},
15+
{"id": "HEAD_DK", "expr": "9.5"},
16+
{"id": "SLOT_LIP_T", "expr": "2.0"},
17+
{"id": "PROFILE", "expr": "20.0"},
18+
{"id": "TNUT_L", "expr": "15.0"},
19+
{"id": "HOLE_CLEAR", "expr": "0.25"},
20+
{"id": "TAB_W", "expr": "5.8"},
21+
{"id": "EDGE", "expr": "3.5"},
22+
{"id": "BED_SCREW_Y", "expr": "10.0"},
23+
{"id": "CROSS_IN", "expr": "2.0"},
24+
{"id": "so_cap", "expr": "screw_offset < 30 ? screw_offset : 30"},
25+
{"id": "so", "expr": "(TNUT_L / 2 + 0.5) > so_cap ? (TNUT_L / 2 + 0.5) : so_cap"},
26+
{"id": "sl_cap", "expr": "stem_length < 40 ? stem_length : 40"},
27+
{"id": "sl", "expr": "(BED_SCREW_Y + HEAD_DK / 2 + 1) > sl_cap ? (BED_SCREW_Y + HEAD_DK / 2 + 1) : sl_cap"},
28+
{"id": "pt_cap", "expr": "plate_t < 5 ? plate_t : 5"},
29+
{"id": "pt", "expr": "4 > pt_cap ? 4 : pt_cap"},
30+
{"id": "half_cross", "expr": "so + HEAD_DK / 2 + EDGE"},
31+
{"id": "hole_d", "expr": "SCREW_D + 2 * HOLE_CLEAR"}
32+
],
33+
"nodes": [
34+
{"id": "crossbar_blank", "type": "box", "params": {"w": {"expr": "half_cross - -half_cross"}, "d": {"expr": "0 - (-PROFILE + CROSS_IN)"}, "h": {"expr": "pt - 0"}}},
35+
{"id": "crossbar", "type": "translate", "inputs": {"shape": "crossbar_blank"}, "params": {"x": {"expr": "(-half_cross + half_cross) / 2"}, "y": {"expr": "(-PROFILE + CROSS_IN + 0) / 2"}, "z": {"expr": "(0 + pt) / 2"}}},
36+
{"id": "stem_blank", "type": "box", "params": {"w": {"expr": "PROFILE / 2 - (-PROFILE / 2)"}, "d": {"expr": "sl - -0.5"}, "h": {"expr": "pt - 0"}}},
37+
{"id": "stem", "type": "translate", "inputs": {"shape": "stem_blank"}, "params": {"x": {"expr": "(-PROFILE / 2 + (PROFILE / 2)) / 2"}, "y": {"expr": "(-0.5 + sl) / 2"}, "z": {"expr": "(0 + pt) / 2"}}},
38+
{"id": "body_1", "type": "union", "inputs": {"a": "crossbar", "b": "stem"}},
39+
{"id": "cross_tongue_blank", "type": "box", "params": {"w": {"expr": "half_cross - 2 - (-half_cross + 2)"}, "d": {"expr": "-PROFILE / 2 + TAB_W / 2 - (-PROFILE / 2 - TAB_W / 2)"}, "h": {"expr": "0.5 - -SLOT_LIP_T"}}},
40+
{"id": "cross_tongue", "type": "translate", "inputs": {"shape": "cross_tongue_blank"}, "params": {"x": {"expr": "(-half_cross + 2 + (half_cross - 2)) / 2"}, "y": {"expr": "(-PROFILE / 2 - TAB_W / 2 + (-PROFILE / 2 + TAB_W / 2)) / 2"}, "z": {"expr": "(-SLOT_LIP_T + 0.5) / 2"}}},
41+
{"id": "body_2", "type": "union", "inputs": {"a": "body_1", "b": "cross_tongue"}},
42+
{"id": "stem_tongue_blank", "type": "box", "params": {"w": {"expr": "TAB_W / 2 - (-TAB_W / 2)"}, "d": {"expr": "sl - 1 - 1"}, "h": {"expr": "0.5 - -SLOT_LIP_T"}}},
43+
{"id": "stem_tongue", "type": "translate", "inputs": {"shape": "stem_tongue_blank"}, "params": {"x": {"expr": "(-TAB_W / 2 + (TAB_W / 2)) / 2"}, "y": {"expr": "(1 + (sl - 1)) / 2"}, "z": {"expr": "(-SLOT_LIP_T + 0.5) / 2"}}},
44+
{"id": "body_3", "type": "union", "inputs": {"a": "body_2", "b": "stem_tongue"}},
45+
{"id": "screw_1_outline", "type": "profile_circle", "params": {"r": {"expr": "hole_d / 2"}, "x": {"expr": "-so"}, "y": {"expr": "-PROFILE / 2"}}},
46+
{"id": "screw_1_blank", "type": "extrude", "inputs": {"profile": "screw_1_outline"}, "params": {"height": {"expr": "pt + 1 - (-SLOT_LIP_T - 1)"}}},
47+
{"id": "screw_1", "type": "translate", "inputs": {"shape": "screw_1_blank"}, "params": {"z": {"expr": "-SLOT_LIP_T - 1"}}},
48+
{"id": "body_4", "type": "cut", "inputs": {"a": "body_3", "b": "screw_1"}},
49+
{"id": "screw_2_outline", "type": "profile_circle", "params": {"r": {"expr": "hole_d / 2"}, "x": {"expr": "so"}, "y": {"expr": "-PROFILE / 2"}}},
50+
{"id": "screw_2_blank", "type": "extrude", "inputs": {"profile": "screw_2_outline"}, "params": {"height": {"expr": "pt + 1 - (-SLOT_LIP_T - 1)"}}},
51+
{"id": "screw_2", "type": "translate", "inputs": {"shape": "screw_2_blank"}, "params": {"z": {"expr": "-SLOT_LIP_T - 1"}}},
52+
{"id": "body_5", "type": "cut", "inputs": {"a": "body_4", "b": "screw_2"}},
53+
{"id": "screw_3_outline", "type": "profile_circle", "params": {"r": {"expr": "hole_d / 2"}, "y": {"expr": "BED_SCREW_Y"}}},
54+
{"id": "screw_3_blank", "type": "extrude", "inputs": {"profile": "screw_3_outline"}, "params": {"height": {"expr": "pt + 1 - (-SLOT_LIP_T - 1)"}}},
55+
{"id": "screw_3", "type": "translate", "inputs": {"shape": "screw_3_blank"}, "params": {"z": {"expr": "-SLOT_LIP_T - 1"}}},
56+
{"id": "body_6", "type": "cut", "inputs": {"a": "body_5", "b": "screw_3"}}
57+
],
58+
"outputs": {
59+
"bed_mount": "body_6"
60+
}
61+
}

‎bed-extrusion-mount/docs/README.md‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,13 @@ A wrong slot station moves the bed extrusion by exactly that error.
9999
- **Wide and Long.** `screw_offset` 20, `stem_length` 26.
100100
- **Thin Plate.** `plate_t` 4, so 6 mm of each M5x10 passes into its T-nut.
101101

102+
## Graph twin
103+
104+
`bed-mount.graph.json` is a node-graph twin of `main.py` (graph format 1.1). It has the same parameters, the same derivations and the same operations in the same order. Each `_box` is a centred `box` translated to its centre, each `_cyl_z` an XY `profile_circle` extruded and translated to its start, and each clamp a min/max ternary pair in `derived`; the constants keep `main.py`'s names, values and sources.
105+
- **Declaration.** The mode declares it as `graph_file` next to the script.
106+
- **Verification.** `y4d-spec check --render --parity` compares the two at the defaults and at every preset (`standard`, `wide_long`, `thin_plate`); they agree to 0.000000 mm.
107+
- **Which one renders.** `main.py` stays the source the platform renders and the oracle the graph is checked against. A script retires only after parity holds across the nightly sweep (owner decision D5, 2026-10-04).
108+
102109
## Hyperobject Profile
103110

104111
- **Domain:** industrial.

‎bed-extrusion-mount/project.json‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
},
4040
"scad_file": "main.py",
4141
"cq_file": "main.py",
42+
"graph_file": "bed-mount.graph.json",
4243
"parts": [
4344
"bed_mount"
4445
],

0 commit comments

Comments
 (0)