@protoboardai/ext-harness-cad 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.
@@ -0,0 +1,170 @@
1
+ ---
2
+ name: harness-cad
3
+ description: Generate a wire harness's routed 3D geometry (conductors along an obstacle-free route through the assembled model, twisted or flat, plug housings, solder joints) through the cad capability (`protoboard run cad:generate|export --module <harness>`, or the harness-cad alias), bind it to the frames its ends land on, and read the route report (length fit, bend radius, clearance). Use after harness-author has the cable (ends, conductors, length, gauge), whenever a part it connects moves, or when HARNESS_NOT_ROUTED / HARNESS_ROUTE_STALE / HARNESS_EXPORT_STALE / HARNESS_ROUTE_LENGTH / HARNESS_ROUTE_WARNING / HARNESS_NOT_CONFIGURED fire.
4
+ ---
5
+
6
+ # Harness CAD
7
+
8
+ A wire harness in UHD is a module (`kind: "harness"`) whose ends are
9
+ connector composites linked to the parts' sockets or to link-scoped
10
+ compositions of pads (see **harness-author**). This skill gives it geometry.
11
+
12
+ How every cable of the reference quadcopter was worked out, modelled, routed
13
+ and drawn: `examples/quadcopter-5in/docs/harnesses-and-cad.md`.
14
+
15
+ ## Purpose
16
+
17
+ Route each cable through the assembled model, so its length is checked
18
+ against a real path, its bend radius and clearance are known, and the
19
+ assembly guide, the viewer and the Manufacturing Package's harness files
20
+ show it. Use it after **harness-author** has the cable, whenever a part it
21
+ connects moves (a board, an enclosure, a plate), and when a `HARNESS_*`
22
+ finding fires. In **build-a-project** it is stage 7, after boards,
23
+ enclosures and structures are placed.
24
+
25
+ ## Inputs
26
+
27
+ | Input | Where | From |
28
+ | --- | --- | --- |
29
+ | The cable: ends, conductors, `performance` (`length_mm`, `conductors`, `wire_gauge_awg`), `cable_build` | the harness definition in `src/harnesses/` | **harness-author** |
30
+ | Frames on every part the cable lands on | sockets' mating faces (xAxis pin 1 → pin N), pads' frames; a board's from `out/board.manifest.json` | the parts, **circuit-board** |
31
+ | Placement of every part | mates, or display placements (`spatial.placements` in `.protoboard/display.json`) for parts nothing mates | **system-compose** |
32
+ | Bodies the cable must clear | each placed part's GLB, designed modules' `out/` | the parts, the providers |
33
+ | The `cad` runtime (build123d + scipy) | `npx protoboard doctor` | `npx protoboard tools install cad` |
34
+
35
+ ## Steps
36
+
37
+ ### 1. Give the cable what it needs
38
+
39
+ On the harness definition:
40
+
41
+ - `performance` trait `{ kind: "cable", length_mm, conductors, wire_gauge_awg? }`
42
+ — the length the geometry is fitted to (bought length, or the length you cut it to);
43
+ - `cable_build` trait — how it is built:
44
+ `{ colors: [...per position of the first end], bundle: "twisted" | "parallel", twist_pitch_mm?, od_mm?, bare?, strip_mm?, spacing_mm?, note, source }`.
45
+ Give `od_mm` when the gauge is not known, and an `assumption` trait saying so.
46
+
47
+ Every part it lands on needs frames: a socket's frame on its mating face
48
+ (xAxis from pin 1 to pin N), each pad's frame on the pad. Parts that no
49
+ mechanical link places (a taped receiver, a capacitor hanging on its leads)
50
+ need a display placement in `.protoboard/display.json`.
51
+
52
+ ### 2. Configure it
53
+
54
+ This extension is a provider of the `cad` capability
55
+ (`docs/specs/tool-integrations.md`). Each cable gets a provider directory with
56
+ a `cad.config.ts`. Cables are usually declared together in one file, so the
57
+ config sits in a folder of its own and names the cable:
58
+
59
+ ```ts
60
+ // src/harnesses/<harness id>/cad.config.ts
61
+ import { defineCapabilityConfig } from "@protoboardai/core";
62
+
63
+ export default defineCapabilityConfig({ provider: "@protoboardai/ext-harness-cad", module: "<harness id>" });
64
+ ```
65
+
66
+ The route (native design) goes to `<dir>/harness-cad/route.json`, the bodies
67
+ (standard outputs) to `<dir>/out/body.{glb,step,manifest.json}`, in
68
+ assembly-root coordinates. Declare them on the harness with
69
+ `harnessCadArtifacts({ dir, name, tool })` from
70
+ `@protoboardai/ext-harness-cad/artifacts`, or let `routedHarness(def, { dir,
71
+ route: readRoute(<route.json>) })` from the same module do it: it declares
72
+ the artifacts and gives each end interface the frame it was routed to and a
73
+ feature ref to its plug or solder joints, so UHD `assemble` places the cable
74
+ from its first end and flags any other end that no longer meets its part
75
+ (the quadcopter's `routed(def)` in `src/harnesses/routes.ts`). It reads the
76
+ route only, never the exported manifest: an export then leaves the
77
+ definition as generate made it, and its record matches the module. Routes are written per definition: a cable used twice
78
+ needs two definitions.
79
+
80
+ ```bash
81
+ npx protoboard capabilities # each cable ✓ bound to @protoboardai/ext-harness-cad
82
+ ```
83
+
84
+ ### 3. Run it
85
+
86
+ ```bash
87
+ npx protoboard tools install cad # once per checkout, if doctor reports python-build123d missing
88
+ # (PROTOBOARD_PYTHON=<python with build123d + scipy> overrides the runtime)
89
+ npx protoboard run cad:generate --module <harness id or instance path> # route → harness-cad/route.json
90
+ npx protoboard run cad:export --module <harness id or instance path> # route → out/ (emptied first)
91
+ npx protoboard run harness-cad --input harness=<id>,<id> # alias: both, for the named cables (every cable without --input), in one routing run
92
+ npx protoboard check # each cable's cad:check + UHD assemble: every routed end still meets its part
93
+ ```
94
+
95
+ `cad:extract` returns the end frames the route was generated for and the
96
+ cable's artifacts, as facts; it does not edit the model.
97
+
98
+ Routing order is the system's (hard rule 2). Generating one cable routes the
99
+ cables before it again, in memory (`data.context` lists them), and writes
100
+ only its own route, so a cable's route is the one a run over the whole
101
+ system gives, whatever was generated before. Regenerating a cable can
102
+ therefore change the cables after it: regenerate those too (the alias does
103
+ all of them in one run).
104
+
105
+ ### 4. Read the report (manifest and op output)
106
+
107
+ | Field | Meaning | Act on |
108
+ | --- | --- | --- |
109
+ | `length_fit.route_mm` | shortest clear route | a cut-to-length cable: set `length_mm` to about this |
110
+ | `length_fit.method` | `shortest`, `bow`, `service loop` (slack laid out in clear space) | `… (not clear)`: the slack does not fit; shorten or re-place |
111
+ | `bend_radius_mm.centreline` | tightest bend away from the terminations | under `minimum` (2.5 × stiffness diameter) is a warning |
112
+ | `clearance_mm.min_conductor_surface` | closest any conductor comes to a solid (negative: inside) | under −0.2 mm is a warning naming the body |
113
+ | `notes` | every finding above, in words | each becomes `HARNESS_ROUTE_WARNING` |
114
+
115
+ Fix the model, not the geometry: move a part (display placement), change the
116
+ socket or pad a cable uses, change the length (cut, or a different cable),
117
+ or change how it is built (flat instead of twisted where it has to pass under
118
+ something). Never edit the generated files (`harness-cad/`, `out/`).
119
+
120
+ ## Decision points
121
+
122
+ | Decision | Rule |
123
+ | --- | --- |
124
+ | One cable or all | The alias (`run harness-cad`) after any change that moves parts: one routing run, and each cable still gets its own `cad:generate` and `cad:export` record (the release traces each cable's `out/` to its `cad:export` record). `cad:generate` then `cad:export` for one cable re-routes the cables before it in memory, so it costs a routing run each. |
125
+ | Cut length | A cut-to-length cable takes `length_fit.route_mm` plus the service loop; a bought cable keeps its listed length and the route must fit it. |
126
+ | A route warning | Change the model (placement, socket, length, build); never accept a conductor inside a solid. |
127
+ | Twisted or parallel | Twisted for signal pairs and where the maker twists them; parallel (flat) where the cable must pass under something. State the choice in `cable_build.note` with its source. |
128
+
129
+ ## Outputs
130
+
131
+ | Output | Where |
132
+ | --- | --- |
133
+ | Route (native design; generated) | `src/harnesses/<harness id>/harness-cad/route.json` |
134
+ | Routed bodies (standard outputs; generated) | `src/harnesses/<harness id>/out/body.glb`, `body.step`, `body.manifest.json` |
135
+ | End frames on the harness | through `routed(def)` / `harnessCadArtifacts` in the harness source |
136
+
137
+ ## Verification
138
+
139
+ ```bash
140
+ npx protoboard check --format json # every cable's cad:check ran with no HARNESS_* warning; no UHD_ASSEMBLY on cable ends
141
+ npx protoboard run harness-cad # a re-run changes no committed file (git status --short src/harnesses)
142
+ ```
143
+
144
+ **harness-verify** compares each cable's modelled length with
145
+ `length_fit.route_mm`.
146
+
147
+ ## Failure handling
148
+
149
+ | Code | Means | Do |
150
+ | --- | --- | --- |
151
+ | `HARNESS_NOT_CONFIGURED` (info, the `routes` check) | A wire harness has no `cad.config.ts` | Add one (step 2) |
152
+ | `HARNESS_NOT_ROUTED` (info) | No route yet | `run cad:generate --module <id>`, then `cad:export` |
153
+ | `REL_STALE` "<cable> changed since its last export" | The cable's definition changed after its export: its model, or (with a hand-written helper) something it reads from its own `out/` | Regenerate and export it; take the end geometry from the route with `routedHarness`, not from `out/body.manifest.json` |
154
+ | `HARNESS_ROUTE_STALE` | The route was generated for other ends, conductors, length or build, or an end no longer meets its part | Regenerate the cable and the ones routed after it (`run harness-cad`) |
155
+ | `HARNESS_EXPORT_STALE` | `out/` is older than the route | `run cad:export --module <id>` |
156
+ | `HARNESS_ROUTE_LENGTH` | Modelled and routed length differ | Regenerate, or set `length_mm` from the route |
157
+ | `HARNESS_ROUTE_WARNING` | Clearance, bend radius or slack | Fix the model (step 4), regenerate |
158
+ | `HARNESS_NOT_ROUTABLE` | The config names a module this provider cannot route | Point it at a wire harness with a `cable_build` trait |
159
+ | `UHD_ASSEMBLY` on a cable end | An end no longer meets its part | Regenerate; if it persists, the part's frame moved: check the part |
160
+ | `UHD_UNPLACED` for a part the cable reaches | Nothing places it | A display placement in `.protoboard/display.json` |
161
+ | `run` refused: tool `python-build123d` missing | No `cad` runtime | `npx protoboard tools install cad` |
162
+
163
+ Every other code: **system-compose** [diagnostic codes](../system-compose/references/diagnostic-codes.md).
164
+
165
+ ## Hard rules
166
+
167
+ 1. Harness ends are generated frames: do not hand-edit them; regenerate.
168
+ 2. Order is rigid first (plug ends and component leads), then flying leads
169
+ thickest first; a cable routed later keeps clear of the earlier ones.
170
+ 3. Every length, gauge and colour is cited on the harness or an `assumption`.
package/README.md DELETED
@@ -1,3 +0,0 @@
1
- # Temporary Holding Version
2
-
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.