@protoboardai/ext-hardware 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.
- package/LICENSE +202 -0
- package/NOTICE +13 -0
- package/checks/evidence.ts +63 -0
- package/evals/compose-probe-cable/case.json +160 -0
- package/evals/e2e-desk-rover/case.json +62 -0
- package/evals/e2e-desk-rover/fixture/AGENTS.md +9 -0
- package/evals/e2e-desk-rover/fixture/docs/brief.md +28 -0
- package/evals/e2e-desk-rover/fixture/docs/decisions.md +3 -0
- package/evals/e2e-desk-rover/fixture/package.json +1 -0
- package/evals/e2e-desk-rover/fixture/protoboard.config.ts +12 -0
- package/evals/e2e-desk-rover/fixture/src/.gitkeep +0 -0
- package/evals/e2e-desk-rover/solution/decisions.md +26 -0
- package/evals/e2e-desk-rover/solution/desk-rover.uhd.ts +60 -0
- package/evals/find-reversed-cell-leads/case.json +78 -0
- package/evals/fix-gnss-uart-swap/case.json +32 -0
- package/evals/fix-two-wiring-faults/case.json +97 -0
- package/evals/rough-draft-is-concept/case.json +36 -0
- package/evals/rough-draft-is-concept/fixture/AGENTS.md +9 -0
- package/evals/rough-draft-is-concept/fixture/docs/brief.md +8 -0
- package/evals/rough-draft-is-concept/fixture/docs/decisions.md +3 -0
- package/evals/rough-draft-is-concept/fixture/package.json +1 -0
- package/evals/rough-draft-is-concept/fixture/protoboard.config.ts +11 -0
- package/evals/rough-draft-is-concept/fixture/src/.gitkeep +0 -0
- package/evals/rough-draft-is-concept/solution/trail-light.uhd.ts +40 -0
- package/evals/tidy-the-diagram/case.json +30 -0
- package/evals/tidy-the-diagram/fixture/.protoboard/display.json +20 -0
- package/evals/tidy-the-diagram/fixture/AGENTS.md +9 -0
- package/evals/tidy-the-diagram/fixture/docs/brief.md +5 -0
- package/evals/tidy-the-diagram/fixture/package.json +1 -0
- package/evals/tidy-the-diagram/fixture/protoboard.config.ts +12 -0
- package/evals/tidy-the-diagram/fixture/src/bike-computer.uhd.ts +63 -0
- package/ops/bom.ts +22 -0
- package/package.json +30 -4
- package/protoboard-extension.json +65 -0
- package/skills/build-a-project/SKILL.md +562 -0
- package/skills/harness-author/SKILL.md +232 -0
- package/skills/harness-author/references/stack-up.md +70 -0
- package/skills/harness-author/references/wire-harnesses.md +35 -0
- package/skills/harness-author/scripts/stackup.ts +104 -0
- package/skills/harness-verify/SKILL.md +112 -0
- package/skills/system-compose/SKILL.md +269 -0
- package/skills/system-compose/references/diagnostic-codes.md +292 -0
- package/skills/system-compose/scripts/scenarios.ts +82 -0
- package/skills/system-review/SKILL.md +145 -0
- package/skills/test-and-measure/SKILL.md +181 -0
- package/skills/test-and-measure/references/procedure-template.md +45 -0
- package/skills/test-and-measure/references/test-plan.md +35 -0
- package/skills/test-and-measure/scripts/test-data.ts +94 -0
- package/README.md +0 -3
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: system-compose
|
|
3
|
+
description: Turn a hardware brief into a checked UHD system in a Protoboard project — requirements, module selection by part tier (cloud catalog, project-researched in parts/local, or designed in src/), a root system with instances, links, harnesses and mates, fault scenarios that prove the checks catch real mistakes — then loop on `protoboard check` until every diagnostic is fixed or dispositioned. Use when starting a system, adding a subsystem, or when `protoboard check` reports errors you need to act on; follow with system-review.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# System compose
|
|
7
|
+
|
|
8
|
+
```
|
|
9
|
+
brief ─► requirements ─► module selection ─► system (instances, links, harnesses, mates)
|
|
10
|
+
│
|
|
11
|
+
fault scenarios ◄──────────┤
|
|
12
|
+
▼
|
|
13
|
+
protoboard check ↻ fix / disposition ─► system-review
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
The UHD model is the design record. Every number in it traces to a source, a
|
|
17
|
+
cited design decision, or an `assumption` trait. A passing check validates the
|
|
18
|
+
model; it never establishes physical readiness.
|
|
19
|
+
|
|
20
|
+
Worked example throughout: `examples/quadcopter-5in` (root
|
|
21
|
+
`src/quadcopter.uhd.ts`, sub-assemblies `src/modules/assemblies.uhd.ts`,
|
|
22
|
+
harnesses `src/harnesses/`, scenarios `src/scenarios.ts`).
|
|
23
|
+
|
|
24
|
+
## Purpose
|
|
25
|
+
|
|
26
|
+
Produce the root system: which modules the product is made of, how they
|
|
27
|
+
connect electrically and mechanically, and the checks that prove the model
|
|
28
|
+
says what the hardware will do. Use it when starting a system from a brief,
|
|
29
|
+
when adding or replacing a subsystem, and whenever `protoboard check`
|
|
30
|
+
reports errors you need to act on. In **build-a-project** it is stage 1
|
|
31
|
+
(requirements) and stage 4 (composition), after the parts exist and before
|
|
32
|
+
boards, enclosures and harness CAD; its check loop (step 5) is also stage 8.
|
|
33
|
+
|
|
34
|
+
## Inputs
|
|
35
|
+
|
|
36
|
+
| Input | Where | From |
|
|
37
|
+
| --- | --- | --- |
|
|
38
|
+
| The brief | `docs/brief.md` | the person asking (with **build-a-project** step 1) |
|
|
39
|
+
| Parts | `parts/catalog/` (cloud catalog), `parts/local/` (project-researched) | `protoboard parts add`, **part-handoff** → **uhd-part-author** |
|
|
40
|
+
| The project config | `protoboard.config.ts`: `root`, `sources` (must include `parts/local/**/*.uhd.ts`), `scenarios` | `protoboard init` |
|
|
41
|
+
| Decisions so far | `docs/decisions.md`, `docs/sourcing/` | **part-search** |
|
|
42
|
+
|
|
43
|
+
## Steps
|
|
44
|
+
|
|
45
|
+
### 1. Brief → requirements
|
|
46
|
+
|
|
47
|
+
1. Read or write `docs/brief.md`: purpose, operating envelope, constraints,
|
|
48
|
+
acceptance targets. Every number gets its source or is labelled a target.
|
|
49
|
+
When the brief has to be written with the person, ask as **build-a-project**
|
|
50
|
+
step 0 says: plain words, every abbreviation spelled out, a typed answer
|
|
51
|
+
always possible, and the level of detail they want agreed first. Before
|
|
52
|
+
describing an existing system to anyone, read it (`npx protoboard inspect`).
|
|
53
|
+
2. Split it into requirements you can check. For each, decide *how* it will be
|
|
54
|
+
shown: a UHD rule (supply budget, link DRC, bus address, propulsion current,
|
|
55
|
+
fastener checks), an assembly check (mates, nut engagement), a document
|
|
56
|
+
value, or a test (see **test-and-measure**). Write that mapping down; the
|
|
57
|
+
review and the test plan both use it.
|
|
58
|
+
3. State the product in `docs/product.json` (schema `protoboard.product/v0`):
|
|
59
|
+
it is what the Manufacturing Package and the datasheet open with, so a
|
|
60
|
+
person can read what the device is before the component detail.
|
|
61
|
+
|
|
62
|
+
```json
|
|
63
|
+
{
|
|
64
|
+
"schema": "protoboard.product/v0",
|
|
65
|
+
"summary": "Two or three sentences: what it is and who it is for.",
|
|
66
|
+
"features": ["What a user gets, one line each"],
|
|
67
|
+
"functions": [{ "id": "F1", "text": "What the system does", "by": "the parts that do it" }],
|
|
68
|
+
"requirements": [{ "id": "R1", "text": "What it must meet", "how": "how it is shown", "pass": "the criterion", "record": "what is written down" }]
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Write it from the brief, in the brief's words; do not write a claim the
|
|
73
|
+
brief does not make. The requirements may stay in the brief instead, as a
|
|
74
|
+
table with the columns ID, Requirement, How, Pass and Record: the
|
|
75
|
+
documents read that table when `requirements` is empty. Keep one of the
|
|
76
|
+
two, not both. Whatever is left empty, the first page says is not stated,
|
|
77
|
+
and `protoboard release --check` warns (`REL_PRODUCT_NOT_STATED`).
|
|
78
|
+
4. Put module-level requirements on the modules they constrain
|
|
79
|
+
(`requirements: [{ type: "capability", description }]`, as on the custom
|
|
80
|
+
frame), and project decisions in `docs/decisions.md` (context, options,
|
|
81
|
+
choice, evidence).
|
|
82
|
+
|
|
83
|
+
### 2. Module selection
|
|
84
|
+
|
|
85
|
+
For each function the brief needs, in this order:
|
|
86
|
+
|
|
87
|
+
| Source | How | Notes |
|
|
88
|
+
| --- | --- | --- |
|
|
89
|
+
| Cloud catalog part | `npx protoboard parts search <words>`, then `npx protoboard parts add <id>` | Vendored from the Protoboard Cloud parts service into `parts/catalog/` (definition, closure and files, and the part's `.uhd.ts` source in `parts/catalog/<id>/`, which is what loads), digest-pinned in `parts/origins.json`. Immutable: read the source, but derive a local variant with its own id (copy the source to `parts/local/`) instead of editing it; `check` reports an edited vendored source as `PB_SOURCE_DRIFT`. The source declares the UHD and TypeScript it needs; the project pins both in `package.json`. Updates are deliberate (`protoboard parts update <id> --to <rev>`). |
|
|
90
|
+
| Purchased part not in the catalog | **part-search** first, then **part-handoff** → **uhd-part-research** → **uhd-part-author** → **uhd-part-verify** | The project-researched tier: `parts/local/<id>.uhd.ts`, its files in `parts/local/<id>/`, evidence in `parts/evidence/<id>/`. The `evidence` check reports parts without sources or verification. Once verified it can be promoted with `protoboard parts publish`. |
|
|
91
|
+
| Custom module (frame, bracket, enclosure, PCB) | design-intent `ModuleDef` in `src/` (`src/modules/`, `src/enclosures/<module>/`, `src/boards/<module>/`) | The project-specific tier. Interfaces first, each mirroring the mating part's interface (cite it). Geometry comes later from them through a capability provider (**frame-cad**, **enclosure-cad**, **circuit-board**). |
|
|
92
|
+
| Mounting hardware, cables | harness modules | See **harness-author**. |
|
|
93
|
+
|
|
94
|
+
Selection rules: lock the exact variant (KV, cell count, revision); prefer
|
|
95
|
+
parts whose interfaces are already modelled; record rejected options with the
|
|
96
|
+
reason in `docs/decisions.md`; never mark an illustrative rating as verified.
|
|
97
|
+
|
|
98
|
+
### 3. Compose the system
|
|
99
|
+
|
|
100
|
+
The root is one exported `ModuleDef` named in `protoboard.config.ts`.
|
|
101
|
+
|
|
102
|
+
- **Instances** (`children`): stable ids; they become instance paths
|
|
103
|
+
(`arm_fl/motor`). Repeated modules get one child each when they are wired
|
|
104
|
+
individually (four arms), or `quantity` when identical and unwired.
|
|
105
|
+
- **Sub-assemblies**: a module with `children`, `links` and `exports` groups
|
|
106
|
+
what is bought or built together (the FC/ESC stack, an arm). Exported
|
|
107
|
+
interfaces let the parent link to `arm_fl:motor__phases` without reaching in.
|
|
108
|
+
A sub-assembly is also a natural Manufacturing Package unit (**release**).
|
|
109
|
+
- **Links**: `{ id, name, a: { child, interfaceId }, b: { child, interfaceId } }`.
|
|
110
|
+
Only link what the hardware actually connects. If the two interfaces do not
|
|
111
|
+
line up (a 3-wire function against 1), read the datasheets; the mismatch is
|
|
112
|
+
information, not something to paper over.
|
|
113
|
+
- **Harnesses**: every physical carrier is a child `kind: "harness"` module.
|
|
114
|
+
Cables are physical: link the parts' sockets to the cable's connector ends
|
|
115
|
+
(or compose a soldered end's pads on the link, `compose`), and UHD derives
|
|
116
|
+
the functional links through the conductors. Mechanical joints are harnesses
|
|
117
|
+
too (fastener stacks); their links name them (`harness: "stack_hardware"`).
|
|
118
|
+
Details in **harness-author**.
|
|
119
|
+
- **Mates**: a link between two mechanical interfaces with frames is a rigid
|
|
120
|
+
mate. `mate: { gapMm, rotationDeg }`; rotations must be multiples of the
|
|
121
|
+
structure's `symmetryDeg`. The assembly is built from links alone; parts
|
|
122
|
+
nothing mates (strapped battery) are reported as unplaced, not guessed. Give
|
|
123
|
+
them a display placement (`spatial.placements` in `.protoboard/display.json`)
|
|
124
|
+
so the viewer, the CAD providers and the documents can place them.
|
|
125
|
+
|
|
126
|
+
Look at it as you go:
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
npx protoboard inspect # instances, definitions by tier, links, artifacts, validator coverage
|
|
130
|
+
npx protoboard dev --open # the system diagram and 3D view, rebuilt on every save; Ctrl+C stops it
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Dragging modules and links in the viewer saves the diagram layout to
|
|
134
|
+
`.protoboard/display.json`. You may write that file yourself to lay the
|
|
135
|
+
diagram out (the project's `AGENTS.md`, "The diagram's layout"); everything
|
|
136
|
+
else under `.protoboard/` is generated. Commit it.
|
|
137
|
+
|
|
138
|
+
### 4. Fault scenarios
|
|
139
|
+
|
|
140
|
+
A check that has never failed proves little. For every rule the design leans
|
|
141
|
+
on, write the realistic mistake it must catch in `src/scenarios.ts` (not a
|
|
142
|
+
`*.uhd.ts` file, so the variants are never loaded as definitions):
|
|
143
|
+
|
|
144
|
+
```ts
|
|
145
|
+
export const SCENARIOS = [
|
|
146
|
+
{ id: "nominal", label: "Nominal build", expect: [] },
|
|
147
|
+
{ id: "gps-on-rx-uart", label: "GPS on the receiver's UART", expect: ["UHD_INTERFACE_REUSE"],
|
|
148
|
+
system: recompose(QUADCOPTER_5IN, "gnss_pads", { p2: "fc:uart2_tx", p3: "fc:uart2_rx" }) },
|
|
149
|
+
{ id: "gnss-rx-tx-swapped", label: "GNSS lead with RX and TX swapped", expect: ["UHD_LINK_STATE"],
|
|
150
|
+
system: recompose(QUADCOPTER_5IN, "gnss_pads", { p2: "fc:uart1_rx", p3: "fc:uart1_tx" }) },
|
|
151
|
+
{ id: "short-gps-screws", label: "M2 × 10 on the GPS", expect: ["UHD_ASSEMBLY"], overrides: [m2x10, gpsShortScrews] },
|
|
152
|
+
];
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
Name the file in `protoboard.config.ts` (`scenarios: { source:
|
|
156
|
+
"src/scenarios.ts", export: "SCENARIOS" }`) so viewers show them, and run
|
|
157
|
+
them:
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
npx tsx node_modules/@protoboardai/ext-hardware/skills/system-compose/scripts/scenarios.ts # [src/scenarios.ts] [--json]
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
Every scenario must print `caught`; the nominal build must raise no errors. A
|
|
164
|
+
`MISSED` fault means a rule is missing, a parameter is absent (DRC cannot
|
|
165
|
+
compare what is not modelled), or the scenario is not the mistake you think.
|
|
166
|
+
Fix the model, not the scenario. Good sources of scenarios: wrong supply rail,
|
|
167
|
+
wrong pattern or fastener size, a shared UART, an address clash, a short screw,
|
|
168
|
+
a wrong-hand prop, a harness connector that does not mate, a board net
|
|
169
|
+
shorted to ground.
|
|
170
|
+
|
|
171
|
+
### 5. The check loop
|
|
172
|
+
|
|
173
|
+
```bash
|
|
174
|
+
npx protoboard check # people: errors and warnings, validator coverage
|
|
175
|
+
npx protoboard check --format json # agents: { checks, diagnostics }
|
|
176
|
+
npx protoboard check --severity info # include infos: what was not checked
|
|
177
|
+
npx protoboard inspect arm_fl/motor --format json # one instance: definition, origin, links, artifacts, diagnostics
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
Read the JSON, not the text:
|
|
181
|
+
|
|
182
|
+
- `diagnostics[]`: `{ code, severity, entity: { kind, id }, message, source: { file, line }, validator }`.
|
|
183
|
+
Go to `source` first; it points at the declaring line.
|
|
184
|
+
- `checks[]`: `{ validator, status: "ran" | "skipped", reason, counts, subject? }`.
|
|
185
|
+
A skipped validator is **unknown, not passed** (e.g. assembly is skipped
|
|
186
|
+
while endpoints are invalid; a provider check is skipped when its tool is
|
|
187
|
+
missing). Fix blocking errors first, then re-run to see the rest.
|
|
188
|
+
|
|
189
|
+
Order of work: loader/registry errors (`PB_*` that stop resolution) → link and
|
|
190
|
+
endpoint errors → UHD rule errors → assembly → geometry bindings → capability
|
|
191
|
+
and extension checks → warnings → infos. After each fix, re-run; one fix often
|
|
192
|
+
clears or reveals others.
|
|
193
|
+
|
|
194
|
+
Every warning ends in one of: fixed; a cited explanation recorded in
|
|
195
|
+
`docs/decisions.md`; or a tracked open item. The quad's one warning,
|
|
196
|
+
`UHD_PROPULSION_CURRENT` (four motors can peak above the pack's continuous
|
|
197
|
+
rating but within its burst rating), is a real finding: it needs a decision
|
|
198
|
+
(accept bursts, limit current in firmware, or choose a higher-rated pack), not
|
|
199
|
+
a deleted parameter. Infos are coverage: read them, they tell you what was not checked.
|
|
200
|
+
|
|
201
|
+
### 6. Hand off
|
|
202
|
+
|
|
203
|
+
When `check` has 0 errors, the scenarios are all caught, and every warning is
|
|
204
|
+
dispositioned: run **system-review** with a fresh agent. Then continue with
|
|
205
|
+
**harness-author**, the designed modules (**circuit-board**,
|
|
206
|
+
**enclosure-cad**, **frame-cad**), **harness-cad**, **firmware-config** and
|
|
207
|
+
**test-and-measure**, in the order **build-a-project** gives.
|
|
208
|
+
|
|
209
|
+
## Decision points
|
|
210
|
+
|
|
211
|
+
| Decision | Rule |
|
|
212
|
+
| --- | --- |
|
|
213
|
+
| Which tier for a part | Catalog if `parts search` has the exact variant; project-researched if not; designed in `src/` only for what is made for this product. Never edit a catalog file. |
|
|
214
|
+
| One child per unit, or `quantity` | One child each when the units are wired or mated individually; `quantity` when identical and unconnected. |
|
|
215
|
+
| Sub-assembly or flat | Group what is bought or built together and what will be a package unit; keep ids stable once others refer to them. |
|
|
216
|
+
| Link two interfaces | Only when the hardware connects them; a mismatch sends you to the datasheets, never to a forced link. |
|
|
217
|
+
| A warning | Fix it, or record a cited disposition in `docs/decisions.md`, or open an item. Removing the parameter it compares is never an option. |
|
|
218
|
+
| A data gap | A `data_gap` trait plus an open item; not a guessed value. |
|
|
219
|
+
|
|
220
|
+
## Outputs
|
|
221
|
+
|
|
222
|
+
| Output | Where |
|
|
223
|
+
| --- | --- |
|
|
224
|
+
| The product statement (summary, features, functions, requirements) | `docs/product.json` |
|
|
225
|
+
| Requirements mapping and decisions | `docs/brief.md`, `docs/decisions.md` |
|
|
226
|
+
| Root system and sub-assemblies | `src/<system>.uhd.ts`, `src/modules/` |
|
|
227
|
+
| Custom module definitions (design intent) | `src/modules/`, `src/boards/<module>/`, `src/enclosures/<module>/` |
|
|
228
|
+
| Fault scenarios | `src/scenarios.ts` |
|
|
229
|
+
| Diagram layout and display placements | `.protoboard/display.json` |
|
|
230
|
+
| Resolved build | `.protoboard/build/resolved.json` (`npx protoboard build`; derived, not committed) |
|
|
231
|
+
|
|
232
|
+
## Verification
|
|
233
|
+
|
|
234
|
+
```bash
|
|
235
|
+
npx protoboard check --format json # 0 errors; every validator in checks[] ran
|
|
236
|
+
npx tsx node_modules/@protoboardai/ext-hardware/skills/system-compose/scripts/scenarios.ts --json # every scenario caught
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
Every warning has a disposition in `docs/decisions.md` or an open item. Then
|
|
240
|
+
**system-review**, by a fresh agent, writes
|
|
241
|
+
`docs/reviews/system-review-<date>.md`.
|
|
242
|
+
|
|
243
|
+
## Failure handling
|
|
244
|
+
|
|
245
|
+
| Code or symptom | Means | Do |
|
|
246
|
+
| --- | --- | --- |
|
|
247
|
+
| `PB_SOURCE_LOAD_FAILED` | A source threw on import | Fix the TypeScript error; nothing in that file loads until then |
|
|
248
|
+
| `PB_UNRESOLVED_DEFINITION` | A child's definition is nowhere | `parts add <id>`, author it in `parts/local/`, or fix the id; check `sources` covers `parts/local/**/*.uhd.ts` |
|
|
249
|
+
| `PB_INVALID_ENDPOINT` | A link names a child or interface that does not exist | Fix the id or add the sub-assembly's export |
|
|
250
|
+
| `UHD_LINK_STATE` | Link DRC found an incompatibility | Relink, change the part, or add the missing parameter from the datasheet |
|
|
251
|
+
| `UHD_SUPPLY_BUDGET`, `UHD_PROPULSION_CURRENT` | A supply or the battery is overloaded | Move loads or choose a stronger source; a warning needs a recorded decision |
|
|
252
|
+
| `UHD_INTERFACE_REUSE`, `UHD_BUS_ADDRESS` | Two devices on one interface or one address | Use a free interface, another bus or another address |
|
|
253
|
+
| `UHD_ASSEMBLY`, `UHD_UNPLACED` | A mate does not close, or a module is not placed | Fix frames, gaps, rotations, hardware lengths; give loose parts a display placement |
|
|
254
|
+
| Scenario `MISSED` | A rule or a parameter is missing | Add the parameter from a source, or accept that the rule does not exist and record it |
|
|
255
|
+
| A validator `skipped` | Unknown coverage | Fix the reason given, re-run |
|
|
256
|
+
|
|
257
|
+
Every other code: [diagnostic codes](references/diagnostic-codes.md).
|
|
258
|
+
|
|
259
|
+
## Hard rules
|
|
260
|
+
|
|
261
|
+
1. Never edit `parts/catalog/*.json`; derive a local variant.
|
|
262
|
+
2. Never silence a diagnostic by removing the parameter it compares. Missing
|
|
263
|
+
data is a `data_gap` trait and an open item.
|
|
264
|
+
3. Never add a link to satisfy a rule (e.g. an "unpowered" warning) that the
|
|
265
|
+
hardware does not have. An input that stays open on purpose is marked on
|
|
266
|
+
its instance instead: `unconnected: [{ interfaceId: "dc_jack", reason:
|
|
267
|
+
"runs from USB" }]`.
|
|
268
|
+
4. Keep ids stable; ids are how links, bindings, documents and releases refer
|
|
269
|
+
to things.
|
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
# Diagnostic codes
|
|
2
|
+
|
|
3
|
+
`protoboard check --format json` returns every finding with a stable `code`.
|
|
4
|
+
Prefixes name the producer: `PB_` framework, `UHD_` UHD validators, `HW_`
|
|
5
|
+
ext-hardware checks, `FRAME_CAD_` and `HARDWARE_CAD_` ext-frame-cad,
|
|
6
|
+
`HARNESS_` ext-harness-cad, `ENCLOSURE_` ext-enclosure-cad, `CIRCUIT_`
|
|
7
|
+
ext-tscircuit, `SRC_` ext-sourcing. Codes are stable; messages are for
|
|
8
|
+
people. Act on the code, read the message for the detail.
|
|
9
|
+
|
|
10
|
+
This is the reference every SOP's **Failure handling** points at. A code you
|
|
11
|
+
do not find here comes from an extension outside this repository:
|
|
12
|
+
`protoboard doctor` lists the installed checks, and the extension's README
|
|
13
|
+
explains its codes.
|
|
14
|
+
|
|
15
|
+
## Framework: loading and resolution (`protoboard/*`)
|
|
16
|
+
|
|
17
|
+
| Code | Severity | Means | Do |
|
|
18
|
+
| --- | --- | --- | --- |
|
|
19
|
+
| `PB_SOURCE_LOAD_FAILED` | error | A `src/**/*.uhd.ts` or `parts/local/**/*.uhd.ts` file threw on import. | Fix the TypeScript error shown; nothing in that file is loaded until then. |
|
|
20
|
+
| `PB_SOURCES_IN_CATALOG` | info | A `sources` glob in `protoboard.config.ts` matches files in the catalog folder (directly or through a link). They are not loaded as the project's code: a vendored part's source is evaluated confined, from `parts/origins.json`. | Narrow `sources` (the default is `src/**/*.uhd.ts` and `parts/local/**/*.uhd.ts`). |
|
|
21
|
+
| `PB_STACK_REPLACE_REFUSED` | error (a command's) | `protoboard stack unpack` (or the extension's "Add the Stack from Another .vsix File") found a copy of the same stack version from another build in `~/.protoboard/stack`, and replacing it was not agreed to. | Replace it only if you trust where the file came from: `protoboard stack unpack <file> --replace`, or answer the extension's question. |
|
|
22
|
+
| `PB_ROOT_NOT_FOUND` | error | `protoboard.config.ts` names a root export that does not exist. | Fix `root.source` / `root.export`. |
|
|
23
|
+
| `PB_DUPLICATE_DEFINITION` | error | Two definitions share an id (e.g. a catalog part and a local edit of it). | Give the local variant its own id; record what it derives from. |
|
|
24
|
+
| `PB_UNRESOLVED_DEFINITION` | error | A child's `moduleDefId` is defined nowhere. | `protoboard parts add <id>`, author it in `parts/local/` (**part-handoff**), or fix the id. Check that `sources` in `protoboard.config.ts` covers `parts/local/**/*.uhd.ts`. Blocks system checks. |
|
|
25
|
+
| `PB_CONTAINMENT_CYCLE` | error | A module contains itself through its children. | Break the cycle. Blocks system checks. |
|
|
26
|
+
| `PB_INVALID_ENDPOINT` | error | A link end names a child or interface that does not exist (or is not exported by a sub-assembly). | Fix the id, or add the export. Blocks system checks. |
|
|
27
|
+
| `PB_UNKNOWN_HARNESS` | error | A link's `harness` is not a child of the declaring module. | Add the harness child, or fix the name. |
|
|
28
|
+
| `PB_MISSING_ARTIFACT` | error | A local artifact file (CAD, generated body) is missing. | Regenerate it (e.g. `protoboard run cad:export --module <id>`) or fix the path. |
|
|
29
|
+
| `PB_ARTIFACT_PATH_UNSAFE` | error or warning | A catalog or vendored part's artifact `filePath` is not a normalised path inside the part's folder: error when it could lead out of it (absolute, `..`, a backslash, a drive, NUL, or a link that points outside), warning when it is only written oddly (`./x`). The file is not resolved, so nothing reads, serves or opens it. | Nothing to do for a warning on a library part. An error means the vendored part was changed or is hostile: `protoboard parts add <id>@<rev>` restores it; remove a link planted in its folder. |
|
|
30
|
+
| `PB_ARTIFACT_UNAVAILABLE` | warning | An optional artifact (vendor/research file, catalog-held, URL-backed) is not present locally. For a catalog part the message gives the revision's reason for not carrying it (redistribution not cleared, not in the source). | Fine offline; materialise it before a release if the release needs it. |
|
|
31
|
+
| `PB_PACKAGE_SCOPE_RENAMED` | error | The project names packages under the stack's former npm scope, `@protoboard/…`: in `package.json`, in `extensions` of `protoboard.config.ts`, or as the `provider` of a capability config. The packages are `@protoboardai/…` since stack 0.1.1; the old name on npmjs is not Protoboard's. One finding lists every place. An import of an old package fails with the same explanation (`protoboard.config.ts: Cannot find package …`, `PB_SOURCE_LOAD_FAILED`, `PB_CAPABILITY_CONFIG_INVALID`). | Replace `@protoboard/` with `@protoboardai/` in those files and in the project's imports, point `@protoboardai:registry` in `.npmrc` at the registry, run `npm install`, then export the bound modules again (their configs changed). Never `npm install` an `@protoboard/…` package. |
|
|
32
|
+
| `PB_BOM_SETTINGS_INVALID` | error | `parts/bom.json` (the units to build and the offers chosen for the bill of materials) is not JSON or not `protoboard.bom-settings/v0`. | Fix what the message names, or delete the file and set it again with `protoboard bom units <n>` and `protoboard bom choose <line> <offer>`. |
|
|
33
|
+
| `PB_FX_RATES_INVALID` | error | `parts/fx-rates.json` (the project's own currency rate table) is not JSON or not `protoboard.fx/v0` (base, date, source, rates). | Fix what the message names, or delete the file: the bill of materials then converts with the dated table the Stack ships. |
|
|
34
|
+
| `PB_EXTENSION_NOT_INSTALLED` | error | `protoboard.config.ts` lists an extension that is not in `node_modules`. | Check the name. The Protoboard installed on the machine carries every extension: `npx protoboard stack` says what the project is linked to. In a project with its own copy of the stack, ask the person before installing the package there. |
|
|
35
|
+
| `PB_EXTENSION_NO_MANIFEST` | error | The package has no `protoboard-extension.json`. | It is not a Protoboard extension; remove it from `extensions`. |
|
|
36
|
+
| `PB_EXTENSION_MANIFEST_INVALID` | error | The manifest breaks the schema: a missing field, a duplicate id, an operation requiring an undeclared tool, a tool runtime with a version range, an invalid capability or view (`contributes.views`) declaration. | Fix the extension (or report it to its author); `protoboard doctor` shows the message. |
|
|
37
|
+
| `PB_EXTENSION_INCOMPATIBLE` | error | The extension needs another framework or UHD version. | Install a compatible version of the extension or the framework. |
|
|
38
|
+
| `PB_EXTENSION_VIEW_DUPLICATE` | warning | Two extensions contribute a view with the same id; the second is ignored. | Rename one of the views (`<extension>.<view>`), or drop one of the extensions. |
|
|
39
|
+
|
|
40
|
+
## Framework: parts and the cloud catalog (`protoboard/catalog`)
|
|
41
|
+
|
|
42
|
+
| Code | Severity | Means | Do |
|
|
43
|
+
| --- | --- | --- | --- |
|
|
44
|
+
| `PB_ORIGIN_MISSING` | error | A catalog JSON has no origin record. | Add it with `protoboard parts add` rather than copying files in. |
|
|
45
|
+
| `PB_DIGEST_MISMATCH` | error | A catalog definition's bytes changed since download. | Re-download it; to change a part, derive a local variant. |
|
|
46
|
+
| `PB_CATALOG_PARSE`, `PB_CATALOG_FILE_MISSING` | error | Broken or missing catalog file. | Re-download with `protoboard parts add <id>@<rev>`. |
|
|
47
|
+
| `PB_VENDORED_FILE_MISMATCH` | error | A file vendored with a catalog revision (CAD, evidence) no longer matches the digest recorded in `parts/origins.json`. | `protoboard parts add <id>@<rev>` restores it; to change the part, derive a local variant. |
|
|
48
|
+
| `PB_VENDORED_FILE_MISSING` | warning | A file vendored with a catalog revision has been deleted. | `protoboard parts add <id>@<rev>` restores it. |
|
|
49
|
+
| `PB_CATALOG_LAYOUT_EARLIER` | info | Vendored parts are in the folder layout of Protoboard 0.1.6 and earlier, whose paths repeat the part id (too long for Windows in a nested project). They load as they are. | `protoboard parts migrate` (offline; the pins stay); commit the moves with `parts/origins.json`. |
|
|
50
|
+
| `PB_SOURCE_DRIFT` | error | A catalog part's vendored `.uhd.ts` source (or a module it imports) no longer evaluates to the definition pinned in `parts/origins.json`: it was edited, or the project's UHD gives another result. The project builds the pinned JSON, not the drifted source. | `protoboard parts add <id>@<rev>` restores the source; to change the part, copy it to `parts/local/` under a new id. |
|
|
51
|
+
| `PB_SOURCE_EDITED` | info | Vendored source differs from what was vendored but still evaluates to the pinned definition (a comment, formatting). | Nothing is wrong; `parts add <id>@<rev>` restores the original. |
|
|
52
|
+
| `PB_SOURCE_LOAD_FAILED` | error | A catalog part's vendored source does not evaluate; the pinned JSON is used. | Restore it with `protoboard parts add <id>@<rev>`. |
|
|
53
|
+
| `PB_SOURCE_LINT` | error | A catalog part's vendored source breaks UHD's lint (an import other than `@deltarobotics/uhd` and its own files, host access such as `process` or `fetch`, `eval`, reflection); it is not evaluated and the pinned JSON is used. | Restore it with `protoboard parts add <id>@<rev>`; to change the part, copy it to `parts/local/` under a new id. |
|
|
54
|
+
| `PB_SOURCE_FILE_MISSING` | warning | A file of a catalog part's vendored source was deleted; the pinned JSON is used. | `protoboard parts add <id>@<rev>` restores it. |
|
|
55
|
+
| `PB_SOURCE_UHD_RANGE`, `PB_SOURCE_UHD_UNKNOWN` | error | The project's `@deltarobotics/uhd` is outside the range the part's source requires (or the project has none). | Pin a UHD in that range, update the part to a revision written for yours, or vendor it `--compiled`. |
|
|
56
|
+
| `PB_SOURCE_TS_RANGE`, `PB_SOURCE_TS_UNPINNED` | warning | The project's TypeScript is outside the range the part's source is written for, or the project does not pin TypeScript. | Pin `typescript` in `package.json` devDependencies. |
|
|
57
|
+
| `PB_UHD_PIN` | warning | `package.json` pins `@deltarobotics/uhd` exactly and another version is installed; the check ran with the installed one. | Run `npm install` to get the pinned version, or move the pin to the installed one (within one minor line, such as 0.2.0 and 0.2.1, parts and definitions need no change). |
|
|
58
|
+
|
|
59
|
+
`parts search`, `parts add`, `parts update` and `parts publish` report
|
|
60
|
+
service problems (service unreachable, part or revision not found,
|
|
61
|
+
incompatible schema) as command errors with exit code 2, not as check
|
|
62
|
+
diagnostics: nothing else talks to the service.
|
|
63
|
+
|
|
64
|
+
## Framework: capabilities and standard outputs (`protoboard/capabilities`, `protoboard/standard-outputs`)
|
|
65
|
+
|
|
66
|
+
The contract behind them is in the stack repository's
|
|
67
|
+
`docs/guides/writing-a-capability-provider.md` ("Diagnostic codes").
|
|
68
|
+
|
|
69
|
+
| Code | Severity | Means | Do |
|
|
70
|
+
| --- | --- | --- | --- |
|
|
71
|
+
| `PB_CAPABILITY_CONFIG_INVALID` | error | A `circuit.config.ts` or `cad.config.ts` does not evaluate, has no default export or provider, or has an invalid `process`. | Fix the config; it is `export default defineCapabilityConfig({ provider, constraints?, module?, process? })`. |
|
|
72
|
+
| `PB_CAPABILITY_CONFIG_UNKNOWN_KEY` | warning | A top-level key other than `provider`, `module`, `constraints`, `process`. | Provider settings go in `constraints`. |
|
|
73
|
+
| `PB_CAPABILITY_MODULE_NOT_FOUND` | error | No module is declared in the config's folder, or `module` names an unknown id. | Put the module's `.uhd.ts` in the folder, or name it with `module: "<id>"`. |
|
|
74
|
+
| `PB_CAPABILITY_MODULE_AMBIGUOUS` | error | The folder declares several modules. | Name the one this config designs with `module: "<id>"`. |
|
|
75
|
+
| `PB_CAPABILITY_DUPLICATE` | error | Two configs of one capability for one module. | Keep one. |
|
|
76
|
+
| `PB_CAPABILITY_CONSTRAINT_UNKNOWN` | warning | A constraint the provider does not declare. | Check the spelling against the provider's README; remove it if it is not the provider's. |
|
|
77
|
+
| `PB_CAPABILITY_CONSTRAINT_MISSING` | error | A constraint the provider requires is absent. | Add it (the message names it). |
|
|
78
|
+
| `PB_PROVIDER_NOT_INSTALLED` | error | The config names a package that is not installed. | As for `PB_EXTENSION_NOT_INSTALLED`: check the name and `npx protoboard stack`; ask the person before installing a package in the project. |
|
|
79
|
+
| `PB_PROVIDER_UNAVAILABLE` | error | Installed, but its manifest did not load. | See its `PB_EXTENSION_*` finding. |
|
|
80
|
+
| `PB_PROVIDER_LACKS_CAPABILITY` | error | The package does not provide this capability. | Name a provider of it (`protoboard capabilities` lists them). |
|
|
81
|
+
| `PB_OUTPUT_NOT_EXPORTED` | info | The module has a config but no outputs of that capability in `out/` yet; the message names the capability (a board may have its circuit outputs and not its firmware's). | `protoboard run <capability>:generate --module <id>`, then `<capability>:export`. |
|
|
82
|
+
| `PB_OUTPUT_STALE` | warning | A file in `out/` is not what the latest export wrote (the record in `operations/`): edited by hand, added, or removed since. `release` refuses it. | Re-run the export the message names; never edit `out/` by hand. |
|
|
83
|
+
| `PB_OUTPUT_MISSING` | error | A required standard output is absent (for `cad`, `process: print` needs STL or 3MF, `cut` needs DXF). | Re-export; if it persists, the provider does not support the process: change `process` or the provider. |
|
|
84
|
+
| `PB_OUTPUT_MALFORMED` | error (some warnings) | A file in `out/` fails its format check (truncated Gerber, a GLB with a wrong header, a CSV without its key column). | Re-export; never edit `out/` by hand. A persistent one is a provider bug. |
|
|
85
|
+
| `PB_OUTPUT_UNKNOWN_INSTANCE` | error | A BOM, PnP or netlist row names an instance the module does not have. | The module changed since export: regenerate and re-export. |
|
|
86
|
+
| `PB_OUTPUT_INCOMPLETE` | warning | A component missing from the BOM or the manifest. | Regenerate and re-export; if it persists, the provider skipped the component (read its export summary). |
|
|
87
|
+
| `PB_EXTRACT_INVALID` | error | Facts from `extract` that do not fit the module (on the operation record, not in `check`). | Re-run `extract` after `generate`; a persistent one is a provider bug. |
|
|
88
|
+
| `PB_VIEW_UNREACHABLE` | warning (a board), info (other modules) | A module has outputs on disk that a viewer tab draws (`out/schematic.svg`, `pcb-top.svg`, `pcb-bottom.svg`, `bom.csv`, a GLB, the routed `circuit.json`) and no artifact names them, so the tab does not appear. The provider attaches its declared outputs by itself; the message says why that did not happen (provider not loaded, no declaration, or the module's own artifact of that id names another file). | Let the provider attach them (drop the module's own artifact of that id), or list them in the module's artifacts; then `protoboard views check --module <id>` shows the tabs. |
|
|
89
|
+
|
|
90
|
+
## Framework: the local viewer (`protoboard dev`)
|
|
91
|
+
|
|
92
|
+
Shown in the viewer's checks panel and the dev log, not by `check`.
|
|
93
|
+
|
|
94
|
+
| Code | Severity | Means | Do |
|
|
95
|
+
| --- | --- | --- | --- |
|
|
96
|
+
| `PB_DEV_BUILD_FAILED` | error | The last rebuild after a change failed; the viewer keeps the last good bundle. | Fix the error in the message (usually a source that does not load), save, and it rebuilds. |
|
|
97
|
+
| `PB_DEV_DISPLAY_INVALID` | error | `.protoboard/display.json` is not valid JSON; the viewer keeps the last valid layout. | Fix the file (or `git checkout` it). |
|
|
98
|
+
| `PB_DEV_LAYOUT_NOT_SAVED` | warning | A layout edit from the viewer could not be written to `display.json`. | Read the reason; the edit stays only in the open page until it is saved. |
|
|
99
|
+
|
|
100
|
+
## Framework: the diagram's layout (`protoboard/layout`)
|
|
101
|
+
|
|
102
|
+
From `check`, for the levels of modules (a board's own sheet is reported by
|
|
103
|
+
`protoboard layout` only).
|
|
104
|
+
|
|
105
|
+
| Code | Severity | Means | Do |
|
|
106
|
+
| --- | --- | --- | --- |
|
|
107
|
+
| `PB_DIAGRAM_LAYOUT` | info | A level of the diagram is hard to read as the viewer draws it: a long row or column of cards (a strip), cards on top of each other, a drawing far from a screen's shape, or many line crossings. The message names the level and the numbers. | `protoboard layout <level>` for the details; fix it with `--apply` (afresh), `--tidy` (your arrangement, fixed) or by moving cards, then look at it in the viewer. Two tries; then say what is left. |
|
|
108
|
+
|
|
109
|
+
## UHD system rules (`uhd/checkSystem`, code = `UHD_` + rule)
|
|
110
|
+
|
|
111
|
+
| Code | Severity | Means | Do |
|
|
112
|
+
| --- | --- | --- | --- |
|
|
113
|
+
| `UHD_LINK_STATE` | error / warning | Link DRC: the two interfaces are incompatible (error: ranges do not overlap, protocols do not match) or need configuration / were matched only by inference (warning). The message names the parameter. | Wrong endpoint → relink. Wrong part → change the part. Missing parameter on one side → add it from the datasheet. Never widen a range to pass. Cable links report here too: `connector_mismatch` / `connector_gender` / `connector_positions` (the plug does not fit the socket), `compose_unknown_slot` (a composition names a position the cable end lacks) and `harness_wiring` (a conductor lands on the wrong pad inside a UART/I2C). Diagnostics on a derived link name the cable links it runs through. |
|
|
114
|
+
| `UHD_SUPPLY_BUDGET` | error / warning / info | Known loads on a supply need more than 100 % (error) or 80 % (warning) of its power; the message lists loads that state no draw. Infos explain branch budgeting or a source with no current rating. | Move loads, choose a stronger rail, or add the missing draw/rating from a source. Unknown loads mean the budget is a lower bound. |
|
|
115
|
+
| `UHD_PROPULSION_CURRENT` | error / warning / info | Motors' combined peak current against the battery's continuous and burst ratings. | Error: redesign. Warning: decide and record (current limit, pack choice). |
|
|
116
|
+
| `UHD_BUS_ADDRESS` | error | Two devices share an address on one bus. | Change an address (if the part allows), use another bus, or drop the device. |
|
|
117
|
+
| `UHD_BUS_PULLUP` | warning | A board net carries I2C but no resistor pulls it up to a supply. | Add the pull-ups to the board module (as components linked to the net), or cite the part that has them on board. |
|
|
118
|
+
| `UHD_NET` | error / warning | A board net is wrong: driven by two supplies, joining ground to a supply (a short), a pin on two nets, a pin rated below the net's voltage, a passive with both terminals on one net, a part's output tied to its own input (VOUT on VIN), a strap pin (such as an address select) on a bus line, or (warning) a net with fewer than two members. | Fix the board's links or the part choice; a one-member net is unfinished or a test point to state. |
|
|
119
|
+
| `UHD_DESIGN_ENVELOPE` | error | A module is bigger than its `design_envelope` trait. | Shrink the design, or revisit the envelope with whoever set it (the brief). |
|
|
120
|
+
| `UHD_PASSIVE_OVERRIDE` | error | A placement's `overrides` on a passive are not ones the part allows, or disagree with its series: a key not in the part's `overridable`, a value outside the series range or not made at the tolerance grade, a value off a table series, an MPN that cannot be formed or that decodes to other parameters. | Fix the board child's `overrides` (the part's `usage_note` with topic `instance` says which keys it takes); name the exact `part_number` where the series cannot form it (Murata GRM). |
|
|
121
|
+
| `UHD_INTERFACE_REUSE` | error | An interface is linked more times than it supports (two devices on one UART). | Use a free interface. |
|
|
122
|
+
| `UHD_UNPOWERED` | warning | A power input has no supply link. | Link the real supply. If the part is powered through a connector modelled elsewhere, model that link. If the input stays open on purpose (a DC jack unused because the product runs from USB, a motor terminal waiting for a battery), mark it on the instance: `unconnected: [{ interfaceId, reason }]`; it is then reported as info with the reason, and the release's test plan does not power it. |
|
|
123
|
+
| `UHD_UNCONNECTED` | warning | An instance marks an interface as unconnected (`ChildModuleRef.unconnected`), but a link connects it, or the mark names an interface the part does not have. | Remove the mark or the link, whichever is wrong; fix the interface id. |
|
|
124
|
+
| `UHD_HARNESS_CONNECTOR` | error | A harness end's connector does not match the interface it mates. | Fix the harness end, or the connector choice. |
|
|
125
|
+
| `UHD_FASTENER_TORQUE` | warning | A fastener joint has no tightening torque, or a torque cites neither source nor assumption. | Add `torque` to the stack item with `source`, or an `assumption` plus the reference tables it was derated from (**harness-author**). |
|
|
126
|
+
| `UHD_PROP_HANDEDNESS` | error / warning | A prop's spin does not match its motor, or spin is not set. | Set `spin` on the instance (`ChildModuleRef.spin`, inherited down the tree: once per arm) and fit the variant that matches. |
|
|
127
|
+
|
|
128
|
+
## UHD assembly (`uhd/assemble`)
|
|
129
|
+
|
|
130
|
+
| Code | Severity | Means | Do |
|
|
131
|
+
| --- | --- | --- | --- |
|
|
132
|
+
| `UHD_ASSEMBLY` | error / warning | A mate is inconsistent: rotation outside the pattern's symmetry ("the holes will not line up"), over-constrained placement, a fastener stack that names a non-child, a nut no screw reaches or a screw that stops short of the nut's far face, harness quantity ≠ stack positions, a mechanical link without frames. | Fix the frame, gap, rotation or hardware length. Rework the stack-up arithmetic (**harness-author**). |
|
|
133
|
+
| `UHD_UNPLACED` | info | A module no mate reaches (strapped battery, receiver). | Expected for strapped/loose parts; give it a display placement (`spatial.placements` in `.protoboard/display.json`) so CAD providers and documents see it; otherwise add the missing mechanical link. |
|
|
134
|
+
|
|
135
|
+
## Geometry bindings (`uhd/geometryBindings`)
|
|
136
|
+
|
|
137
|
+
| Code | Severity | Means | Do |
|
|
138
|
+
| --- | --- | --- | --- |
|
|
139
|
+
| `UHD_GEOMETRY_BINDING` | error | A feature ref names an artifact the module lacks, a feature not in the manifest ("renamed or removed in the CAD?"), or a feature whose signature changed since binding ("re-bind explicitly"). | Review the CAD change. If intended: re-bind (**frame-cad**: `protoboard run frame-cad-rebind`; another `cad` provider: copy the frames `cad:extract` returns; hand-authored CAD: update the `feature(...)` signature). If not: fix the CAD. |
|
|
140
|
+
|
|
141
|
+
The check's `reason` also reports refs with no manifest (e.g. KCL sources):
|
|
142
|
+
those are unknown, not passed.
|
|
143
|
+
|
|
144
|
+
## ext-hardware (`ext:@protoboardai/ext-hardware/evidence`)
|
|
145
|
+
|
|
146
|
+
| Code | Severity | Means | Do |
|
|
147
|
+
| --- | --- | --- | --- |
|
|
148
|
+
| `HW_NO_SOURCES` | warning | A purchased part cites no sources. | **uhd-part-research**; or cite the supplier listing on hardware. |
|
|
149
|
+
| `HW_NOT_VERIFIED` | info | Sources but no recorded verification. | **uhd-part-verify**. |
|
|
150
|
+
| `HW_VERIFICATION_WRONG` | error | The audit found wrong facts with no recorded repair. | Repair with **uhd-part-author** (repair mode), re-verify. |
|
|
151
|
+
| `HW_VERIFICATION_REPAIRED` | info | Wrong facts were found and repaired. | Nothing; kept for traceability. |
|
|
152
|
+
| `HW_VERIFICATION_SELF_AUDIT` | info | The part's verification record is a self-audit (`audit.independent: false`): the agent that authored it checked it. | Run the independent stage-2 audit (**uhd-part-verify**) and record it with `--independent`. |
|
|
153
|
+
|
|
154
|
+
## ext-sourcing (`ext:@protoboardai/ext-sourcing/sourcing`)
|
|
155
|
+
|
|
156
|
+
Full table with the rules behind each: **supplier-compare** section 3.
|
|
157
|
+
|
|
158
|
+
| Code | Severity | Means | Do |
|
|
159
|
+
| --- | --- | --- | --- |
|
|
160
|
+
| `SRC_RECORD_INVALID`, `SRC_OFFER_INCOMPLETE` | error | A malformed `sourcing.json`, or a figure without supplier, MPN, URL, date or method. | Fix the record (**supplier-compare**). |
|
|
161
|
+
| `SRC_FORBIDDEN_FIELD`, `SRC_CREDENTIAL_IN_URL` | error | An order, cart or credential field, or a key in a URL. | Remove it; store the public product URL. Never commit a credential. |
|
|
162
|
+
| `SRC_SINGLE_SOURCE`, `SRC_LOW_STOCK`, `SRC_LIFECYCLE` | warning | A selection disqualifier nobody accepted. | Name an alternate (**lifecycle-alternates**), or a named person accepts the risk in `risks[]`. |
|
|
163
|
+
| `SRC_NO_OFFER`, `SRC_OFFER_MPN_MISMATCH` | warning | No offer with stock, or an offer for another ordering code. | Read more suppliers, or record the sibling code as an alternate. |
|
|
164
|
+
| `SRC_PART_MISMATCH`, `SRC_UNKNOWN_PART` | warning | A record in the wrong folder, or for an id the project does not define. | Move or rename the record. |
|
|
165
|
+
| `SRC_RISK_ACCEPTED` | info | A disqualifier a named person accepted. | Nothing; kept for traceability. |
|
|
166
|
+
| `SRC_STALE` | info | Newest offer older than 90 days. | Re-read offers before quoting anything (**supplier-compare**). |
|
|
167
|
+
| `SRC_UNVERIFIED`, `SRC_NO_CAPABILITY`, `SRC_LIFECYCLE_UNKNOWN`, `SRC_STOCK_UNKNOWN` | info | Coverage gaps. | Close them, or say in the record why they stay open. |
|
|
168
|
+
|
|
169
|
+
## ext-frame-cad (`ext:@protoboardai/ext-frame-cad/cad:check`, one run per plate; `…/frames`, `…/hardware`)
|
|
170
|
+
|
|
171
|
+
| Code | Severity | Means | Do |
|
|
172
|
+
| --- | --- | --- | --- |
|
|
173
|
+
| `FRAME_CAD_NOT_CONFIGURED` | info | A plate module has no `cad.config.ts` (the `frames` check). | Add one naming `@protoboardai/ext-frame-cad` in its folder (**frame-cad**). |
|
|
174
|
+
| `FRAME_CAD_NOT_A_PLATE` | error | The config points ext-frame-cad at a module that is not a plate (no `plate_thickness_mm`). | Add the plate's mechanical metadata, or name another `cad` provider (an enclosure: `@protoboardai/ext-enclosure-cad`). |
|
|
175
|
+
| `FRAME_CAD_NOT_GENERATED` | info | A plate module has no generated CAD yet. | `protoboard run cad:generate --module <id>`, then `cad:export`. |
|
|
176
|
+
| `FRAME_CAD_STALE` | warning | The interfaces or design values (config constraints) changed since the CAD was generated. | Regenerate; then review the returned re-bind list. |
|
|
177
|
+
| `FRAME_CAD_EXPORT_STALE` | warning | `out/` was exported from other parameters than the native design. | `protoboard run cad:export --module <id>`. |
|
|
178
|
+
| `FRAME_CAD_FRAME_MISMATCH` | error | A module frame differs from the generated plate's frame. | Review; `protoboard run frame-cad-rebind` if the new plate is right. Check dependent stack-ups. |
|
|
179
|
+
| `FRAME_CAD_UNKNOWN_INTERFACE` | error | Generated frames name an interface the module no longer has. | Regenerate after renaming/removing. |
|
|
180
|
+
| `FRAME_CAD_FRAME_MISSING` | warning | Generated geometry exists for an interface without a model frame. | Add the frame (re-bind). |
|
|
181
|
+
| `HARDWARE_CAD_PARAMS` | error | A local fastener module lacks a size the hardware generator needs (diameter, length, head or across-flats size). | Add it from the supplier listing (**harness-author** step 3); nothing is defaulted. |
|
|
182
|
+
| `HARDWARE_CAD_STALE` | warning | A fastener module's sizes changed since its body was generated. | `protoboard run cad:generate --module <id>`, then `cad:export` (or `run hardware-cad --input module=<id>` while iterating). |
|
|
183
|
+
| `HARDWARE_CAD_EXPORT_STALE` | warning | A fastener module's `out/` was exported from other params than its native `frame-cad/params.json`. | `protoboard run cad:export --module <id>`. |
|
|
184
|
+
| `HARDWARE_CAD_NOT_GENERATED`, `HARDWARE_CAD_NOT_CONFIGURED` | info | A bound fastener module has no params yet; a local fastener module has no body and no `cad.config.ts`. | Generate it; or add `parts/local/<id>/cad.config.ts` naming @protoboardai/ext-frame-cad (**frame-cad** step 6). |
|
|
185
|
+
| `PART_CAD_STALE`, `PART_CAD_EXPORT_STALE` | warning | A researched part's body script changed since generate, or its `out/` is from another generate. | `protoboard run cad:generate --module <id>`, then `cad:export` (**uhd-part-author**, In a project). |
|
|
186
|
+
| `PART_CAD_CONFIG`, `PART_CAD_NOT_GENERATED` | error, info | The part's `cad.config.ts` names no script in `part-cad/`, or it was never generated. | Fix `constraints.generator`; run generate and export. |
|
|
187
|
+
|
|
188
|
+
## ext-harness-cad (`ext:@protoboardai/ext-harness-cad/cad:check`, one run per cable; `…/routes`)
|
|
189
|
+
|
|
190
|
+
| Code | Severity | Means | Do |
|
|
191
|
+
| --- | --- | --- | --- |
|
|
192
|
+
| `HARNESS_NOT_CONFIGURED` | info | A wire harness has no `cad.config.ts` (the `routes` check). | Add one naming `@protoboardai/ext-harness-cad` (**harness-cad**). |
|
|
193
|
+
| `HARNESS_NOT_ROUTED` | info | No route yet. | `protoboard run cad:generate --module <id>`, then `cad:export`. |
|
|
194
|
+
| `HARNESS_ROUTE_STALE` | warning | 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). |
|
|
195
|
+
| `HARNESS_EXPORT_STALE` | warning | `out/` was exported from an earlier route. | `protoboard run cad:export --module <id>`. |
|
|
196
|
+
| `HARNESS_ROUTE_LENGTH` | warning | Modelled and routed length differ. | Regenerate, or fix the length (**harness-cad**). |
|
|
197
|
+
| `HARNESS_ROUTE_WARNING` | warning | The router's own finding (clearance, bend radius, slack). | Fix the model, not the geometry (**harness-cad**). |
|
|
198
|
+
| `HARNESS_NOT_ROUTABLE` | error | The config names a module this provider cannot route. | Point the config at a wire harness with a `cable_build` trait. |
|
|
199
|
+
|
|
200
|
+
## ext-enclosure-cad (`ext:@protoboardai/ext-enclosure-cad/cad:check`, one run per enclosure)
|
|
201
|
+
|
|
202
|
+
Details of every check: the package README, "Checks". Usual fixes:
|
|
203
|
+
**enclosure-cad** "Failure handling".
|
|
204
|
+
|
|
205
|
+
| Code | Severity | Means | Do |
|
|
206
|
+
| --- | --- | --- | --- |
|
|
207
|
+
| `ENCLOSURE_NOT_GENERATED` | info | No generated design yet. | `protoboard run cad:generate --module <id>`, then `cad:export`. |
|
|
208
|
+
| `ENCLOSURE_FEATURE_INVALID` | error | A feature interface the provider cannot read. | Build the feature with the extension's builders (`Opening`, `Button`, …). |
|
|
209
|
+
| `ENCLOSURE_INPUT` | error | The model does not say enough (a served part with no frame, the enclosure not placed). | Add the frame or placement the message names. |
|
|
210
|
+
| `ENCLOSURE_STALE` | warning | Contents, features, design values or the job changed since generation (listed). | Review what changed, then regenerate. |
|
|
211
|
+
| `ENCLOSURE_NATIVE_EDITED` | info | The native design was edited after its last build. | `cad:export` rebuilds from it; `cad:generate` replaces it from the model. |
|
|
212
|
+
| `ENCLOSURE_GENERATOR_STALE` | warning | The design was built by another version of the generator: its recorded `sourceDigest` is not what `py/enclosure_cad.py` and `py/fit.py` give for its job now. `release` refuses it (`REL_STALE`). | `cad:generate` and `cad:export`, then review the diff (often only the digest lines change). |
|
|
213
|
+
| `ENCLOSURE_FEATURE_MISSING` | error | An interface with no generated feature, or the reverse. | Regenerate. |
|
|
214
|
+
| `ENCLOSURE_FRAME_MISMATCH` | error | A declared frame differs from the generated one. | Regenerate; take the frames from `cad:extract`. |
|
|
215
|
+
| `ENCLOSURE_GENERATOR` | error | A problem the generator reported (no room for a plunger flange, a feature that cut nothing, a frame off its surface). | Read the message; move the part or change the feature. |
|
|
216
|
+
| `ENCLOSURE_COLLISION` | error | A body inside intersects a wall, boss or column, or a plunger intersects a wall or a body. | Regenerate; if it persists, move the part, add a board cutout or set `cavity_mm`. |
|
|
217
|
+
| `ENCLOSURE_NOT_CONTAINED` | error | A body reaches outside the cavity. | As for a collision. |
|
|
218
|
+
| `ENCLOSURE_CLEARANCE` | warning | A body is closer to a wall than the design clearance. | Raise `clearance_mm`, or accept the contact and say so in the module. |
|
|
219
|
+
| `ENCLOSURE_FIT_UNCHECKED` | warning | The contents changed and Python is not available to re-analyse the fit. | `protoboard tools install cad`, then `protoboard check`. |
|
|
220
|
+
| `ENCLOSURE_THIN_WALL` | error / warning | Below the minimum wall. | Thicker `wall_mm`/`lid_mm`, a smaller cut, or move the feature. |
|
|
221
|
+
| `ENCLOSURE_MISALIGNED` | error | An opening, window, light pipe or plunger off the axis of what it serves. | The served part moved: regenerate. |
|
|
222
|
+
| `ENCLOSURE_RECESS` | error | The served part sits deeper behind an opening than allowed. | Move the part to the wall, or size the opening for the plug's overmold. |
|
|
223
|
+
| `ENCLOSURE_PLUNGER` | error | A plunger presses its switch at rest, cannot reach it, or its flange no longer holds. | Change `gapMm`/`protrudeMm`, or move the switch. |
|
|
224
|
+
| `ENCLOSURE_PLUG_FIT` | error / warning | The plug does not pass the opening, or its overmold has no flat seat. | Size or move the opening. |
|
|
225
|
+
| `ENCLOSURE_SEAL_SQUEEZE` | error | O-ring squeeze outside the chart row for its cross-section. | Choose the AS568 size that fits the groove; do not edit gland depths away from the table. |
|
|
226
|
+
| `ENCLOSURE_SEAL_FIT` | error / warning | Stretch over 5 %, or a face groove not sized to the O-ring. | Choose another AS568 size. |
|
|
227
|
+
| `ENCLOSURE_ENVELOPE` | error | Bigger than the module's `design_envelope`. | Thinner walls, a tighter cavity, or revisit the envelope with the brief's owner. |
|
|
228
|
+
|
|
229
|
+
## ext-tscircuit (`ext:@protoboardai/ext-tscircuit/circuit:check`, one run per board)
|
|
230
|
+
|
|
231
|
+
Details: the package README, "check". Usual fixes: **circuit-board**
|
|
232
|
+
"Failure handling".
|
|
233
|
+
|
|
234
|
+
| Code | Severity | Means | Do |
|
|
235
|
+
| --- | --- | --- | --- |
|
|
236
|
+
| `CIRCUIT_BOARD_UNREADABLE` | error | The UHD board cannot be read as a netlist: a component's part is undefined, a pin has no designator, a link joins a composite interface to a pin or a net (two functional ports linked directly are copper), two declared nets of one module are joined, a link reaches a sub-module's own net or a separate board, nets on one conductor state different voltages, or a sub-module has a quantity. | Fix the board module (or the part: **uhd-part-author** adds pin designators). |
|
|
237
|
+
| `CIRCUIT_BOARD_GROUPING` | warning | A board's sub-module declares an export the board neither links nor re-exports, or a sub-module contributes no parts (docs/specs/nested-boards.md §11). | Link the export, or mark it `unconnected` on the child with the reason. |
|
|
238
|
+
| `CIRCUIT_NOT_BUILT` | info | No build yet. | `protoboard run circuit:generate --module <id>`. |
|
|
239
|
+
| `CIRCUIT_STALE` | warning | The UHD board, `layout.json`, `footprints.json` or the constraints changed since generate, or the native source (or a file it imports, JSON included) since the build; or `out/` was exported from other inputs (what the board depends on in UHD, not descriptions or prices; a body; the provider; a converter). | `protoboard run circuit:generate --module <id>`, then `circuit:export`. |
|
|
240
|
+
| `CIRCUIT_DRC` | error | tscircuit's own DRC, or `@tscircuit/checks`, found an error. | Move parts (`layout.json`), widen the board, or change rules; regenerate. |
|
|
241
|
+
| `CIRCUIT_NET_OPEN`, `CIRCUIT_NET_SHORT`, `CIRCUIT_NET_EXTRA`, `CIRCUIT_UNROUTED`, `CIRCUIT_PIN_MISSING` | error | The copper's nets differ from the UHD board's nets. | Regenerate; if routing cannot complete, give parts room (`layout.json`, a larger outline, 4 layers). Never change the UHD nets to match the copper. |
|
|
242
|
+
| `CIRCUIT_PAD_UNNETTED` | error | A pin with several pads (a module's exposed ground pads) has pads the copper does not join to its net; boards generated before 0.1.7 netted only the first pad. | `protoboard run circuit:generate --module <id>` (it joins the pin's pads to each other), then `circuit:export`. |
|
|
243
|
+
| `CIRCUIT_FINGERPRINT_FORMAT` | info | `tscircuit/export.json` was written by a provider that fingerprinted the whole UHD module; the board's own dependencies are fingerprinted now, so the record is not compared for the board (no false stale). | `protoboard run circuit:export --module <id>` once. |
|
|
244
|
+
| `CIRCUIT_FOOTPRINT_FAMILY` | info | A part's land pattern was chosen by its package family (`SOT23-5L` → the `SOT-23-5` entry), its stated pin count, pitch and size agreeing. | Nothing; confirm the pattern when the part is unusual. |
|
|
245
|
+
| `CIRCUIT_FOOTPRINT_MISMATCH` | error | Land patterns of the part's package name or family exist, but none fits its facts (pin count, pitch, body size); the provider reports it instead of picking one. | Correct the part's package facts, or add a fitting entry to `tscircuit/footprints.json`. |
|
|
246
|
+
| `CIRCUIT_VIA_TOUCHING_PAD` | error | A via's ring touches an SMD pad it does not sit in, with `via_touching_pad: "avoid"`. | Move parts a little and regenerate. |
|
|
247
|
+
| `CIRCUIT_VIA_UNDER_BODY` | error | A via lies inside a component's courtyard, with `via_under_body: "avoid"`. | Give the parts room and regenerate. |
|
|
248
|
+
| `CIRCUIT_HOLE_CLEARANCE` | error | Copper (pad, plated hole, via, trace, pour) closer to a non-plated hole's wall than `rules.hole_clearance_mm` (or inside the hole); round holes are tested as circles. | Move the copper or the hole; regenerate. |
|
|
249
|
+
| `CIRCUIT_TRACE_WIDTH` | warning | A net is routed narrower than `trace_widths` asks for (the router necks traces down where the width does not fit). | Give the net room, or accept the neck-down. |
|
|
250
|
+
| `CIRCUIT_COMPONENT_MISSING`, `CIRCUIT_COMPONENT_EXTRA` | error | A UHD component is not on the board, or the board has one UHD lacks. | Regenerate; remove hand-added parts from `board.tsx`. |
|
|
251
|
+
| `CIRCUIT_OUTSIDE_OUTLINE` | error / warning | A pad off the board / a body overhanging the edge. | Move the part in `layout.json` or the config's `placements`, or enlarge the outline. |
|
|
252
|
+
| `CIRCUIT_KEEPOUT` | error / warning | Copper inside a keep-out / a keep-out that misses the board or both copper layers. | Move the part or trace; fix the keep-out's position or layers. |
|
|
253
|
+
| `CIRCUIT_PLACEMENT_MOVED` | error | A part the config fixes is somewhere else. | Remove the hand override in `board.tsx`/`layout.json`, regenerate. |
|
|
254
|
+
| `CIRCUIT_FOOTPRINT_UNVERIFIED` | warning | A land pattern the board uses has no verification record against its maker's recommended land pattern, or differs from it (pads, pitch, rows, slots, holes, courtyard, paste, mask). The board's work order holds while any is left. | Author the record from the maker's drawing (**circuit-board** step 2b), or fix the pads it names. |
|
|
255
|
+
| `CIRCUIT_VIA_IN_PAD` | error / info | A via inside an SMD pad / the same, with `via_in_pad: "fill_and_cap"` (the order asks the fab to fill and cap it). | Move parts and regenerate, or allow it with the fill-and-cap note. |
|
|
256
|
+
| `CIRCUIT_CONFIG_INVALID` | error | A `circuit.config.ts` constraint has the wrong type or value (outline, placements, keep-outs, or a fab-order key: `copper_oz` not a positive number, an empty `finish`, `solder_mask` or `silkscreen`, `assembly` not "fab" or "hand"). `circuit:generate` refuses it, and the release would print it wrong in the board order. | Fix the value the message names in `circuit.config.ts`, then regenerate. |
|
|
257
|
+
| `CIRCUIT_LOCKED` | info | The board is locked: KiCad (`<board dir>/kicad/`) is its layout of record since the handoff; tscircuit's build is not checked. | Review and finish it in KiCad (**kicad-layout-review**); `circuit:unlock` only when the person decides. |
|
|
258
|
+
| `CIRCUIT_KICAD_STALE` | error | Since lock the model added or removed a part or changed a land pattern, or the outline, holes, layers or thickness changed, and the KiCad board lacks it. | Make the change in KiCad (Update PCB from Schematic, place, route), or propose unlocking and regenerating. |
|
|
259
|
+
| `CIRCUIT_KICAD_MODEL_CHANGED`, `CIRCUIT_KICAD_FIELDS` | warning | Since lock connections between existing parts changed in the model (net renamed, pin moved), or an MPN, manufacturer, value or LCSC number. | Make the same change in the KiCad schematic and board; then `circuit:lock --input refresh=true`, asked first. |
|
|
260
|
+
| `CIRCUIT_KICAD_APPLIED` | info | A model change since lock is in KiCad too. | Ask, then `protoboard run circuit:lock --module <id> --input refresh=true` records it. |
|
|
261
|
+
| `CIRCUIT_KICAD_PART_MISSING`, `CIRCUIT_KICAD_NET_CHANGED` | error | A part was deleted, or a pin moved to another net, in KiCad, and the model does not say so. | Undo it in KiCad; if the change is wanted, make it in the UHD board module first. Nothing is written back. |
|
|
262
|
+
| `CIRCUIT_KICAD_PART_EXTRA`, `CIRCUIT_KICAD_FOOTPRINT_CHANGED`, `CIRCUIT_KICAD_NET_RENAMED`, `CIRCUIT_KICAD_PARITY` | warning | KiCad has a part the model lacks, a swapped footprint, a renamed net, or a schematic that disagrees with its board. | Add the part to the model or remove it in KiCad; restore the footprint or name; Update PCB from Schematic. |
|
|
263
|
+
| `CIRCUIT_KICAD_DRC` | error / warning / info | KiCad's own DRC of a locked board (`kicad-cli pcb drc --format json --severity-all --schematic-parity`, the same run and count as `circuit:export`): errors or unconnected items are an error, warnings alone a warning. Without kicad-cli it is read from the last export's `out/drc.json` (said when the board changed since), else info. | Fix the layout in KiCad (Inspect > Design Rules Checker; the kicad-layout-review skill). A forced export does not make it pass. |
|
|
264
|
+
| `CIRCUIT_VIA_RULES` | error | A via smaller than the config's `rules.via_pad_mm` / `via_drill_mm` (a via written by hand). | Make it to the rules, or change the rules if the fab can make it. |
|
|
265
|
+
| `CIRCUIT_HAND_PAD_JOIN` | warning | A trace written by hand in `board.tsx` joins pads of one pin, which generate joins itself (since 0.1.7); in KiCad it is copper on no net. | Remove the trace from `board.tsx`, then generate. |
|
|
266
|
+
| `CIRCUIT_KICAD_UNREADABLE` | error | A locked board's KiCad file is missing or cannot be parsed. | Restore it from git, or re-save it from KiCad 10. |
|
|
267
|
+
|
|
268
|
+
## Codes from firmware providers, releases and sections
|
|
269
|
+
|
|
270
|
+
Three more families come from operations rather than from the checks above;
|
|
271
|
+
their own references hold the full tables.
|
|
272
|
+
|
|
273
|
+
| Family | Where it shows | Reference |
|
|
274
|
+
| --- | --- | --- |
|
|
275
|
+
| `FW_*` | `ext:@protoboardai/ext-zephyr/firmware:check` and `ext:@protoboardai/ext-esp-idf/firmware:check` in `protoboard check` (one run per board), and a refused `firmware:generate` | [Writing a capability provider](../../../../../docs/guides/writing-a-capability-provider.md#diagnostic-codes) (firmware table), and the **firmware-config-zephyr** / **firmware-config-esp-idf** SOPs |
|
|
276
|
+
| `REL_*` | `protoboard release` and `protoboard release --check` (its preconditions and sections; nothing is written while any is an error) | [ext-release README](../../../../ext-release/README.md#preconditions) |
|
|
277
|
+
| `DRONE_CLI_MISSING`, `DRONE_CLI_STALE` | `protoboard release`: ext-drone's work-order section when `firmware/betaflight/cli.txt` is missing or no longer matches the model | Run `protoboard run betaflight-cli`, review the diff, commit, release again (**firmware-config**) |
|
|
278
|
+
|
|
279
|
+
## Reading a finding
|
|
280
|
+
|
|
281
|
+
```json
|
|
282
|
+
{ "code": "UHD_LINK_STATE", "severity": "error",
|
|
283
|
+
"entity": { "kind": "link", "id": "video_power" },
|
|
284
|
+
"message": "O4 10V: incompatible — voltage: 18–25.2 V vs 3.7–13.2 V (ranges do not overlap)",
|
|
285
|
+
"source": { "file": "src/quadcopter.uhd.ts" }, "validator": "uhd/checkSystem" }
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
`entity` says what to open (`protoboard inspect <instance>` for instances;
|
|
289
|
+
the link id for links). `source` is the declaring file, with a line when the id can be located. `validator` tells you
|
|
290
|
+
which check to re-run mentally after the fix; a provider's check carries the
|
|
291
|
+
module in `subject` (`checks[]`). A check that was `skipped` (a missing tool,
|
|
292
|
+
a blocking error upstream) is unknown, not passed.
|