# DFM Knowledge Packs — the design-for-manufacturing database (CADSF-1106)

`ops/dfmRules.js` answers *can this body be made by process X at shop Y?* — a
checkable verdict on geometry. It knows nothing about what a **chair**, a
**keyboard plate** or a **Raspberry Pi enclosure** should be. A text-to-CAD
agent asked for one has to know the seat height, the 19.05 mm key pitch, the
M2.5 standoff pattern — before it calls a single modelling tool.

Knowledge packs are that layer: **sector-organised design facts an agent loads
before it models**, in a shape it can search, in three sizes, one file per
sector so a session pays only for the sectors it uses.

Surface: `ops/designKnowledge.js` (kernel) and the MCP tool
`cad_design_knowledge` (CADSF-1107). Data: `data/dfm/packs/<sector>.json`.
Built artefacts: `data/dfm/dist/` (per-size bundles, byte-counted) and
`data/dfm/packs/index.js` (static requires so the staged kernel ships every
pack). Gate: `tests/test_cadsf-1106.js` validates every pack on every push.

---

## Shipped packs (Data Loop sprint additions)

| Pack | Sector | Entries (core/std/full) | Recipes | Ticket |
|---|---|---|---|---|
| `desk-everyday` | stands, holders, hooks, boxes, organisers (phone/laptop/headphone stand, monitor riser, pen holder, bookend, coaster, cable clip, keychain, wall hook, hinged box, drawer organiser, soap dish, toothbrush holder) | 18 / 51 / 54 | 3 (phone stand, pen holder, coaster) | CADSF-1132 |
| `maker-enclosures` | Raspberry Pi / Arduino / ESP32 dev-board cases and project boxes (Pi Zero, Nano, NodeMCU, Jetson Nano, CM4, HATs, fan grills, DIN-rail, snap/screw lids) — board outlines electronics.json doesn't cover, plus maker-specific fit/vent/lid/material rules | 15 / 39 / 40 | 3 (Pi 4 case base, Pico case, 40 mm fan-grill plate) | CADSF-1136 |
| `mounts-brackets` | VESA/tripod/GoPro/Arca-Swiss mounting interfaces, bike clamp diameters, shelf/L-bracket structural rules, wall-anchor and T-slot extrusion fasteners, materials and the load/vibration/drop tests a mount or bracket is held to | 17 / 47 / 54 | 4 (VESA-100 adapter plate, gusseted L-bracket, GoPro 3-finger mount, sheet-folded L-bracket on the scs_laser+scs_bend route) | CADSF-1137 |
| `kitchen-tableware` | mugs, tumblers, mixing bowls, plates, water bottles, cutlery, funnels, teapots/kettles, chopping boards, knife handles, jar lids — wall-thickness, handle-attachment, thread, nesting/stacking and food-contact-material facts for kitchenware | 22 / 44 / 44 | 3 (coffee mug with D-handle, mixing bowl, cookie cutter) | CADSF-1133 |
| `power-transmission` | spur/helical/bevel/worm/planetary gears, roller chain and sprockets, rack-and-pinion, V-belts and timing belts, cams, clutches, shaft fits and the tooth-bending-fatigue/chain-wear/belt-tension/NVH tests a drivetrain component is held to | 18 / 46 / 46 | 3 (20-tooth module-2 spur gear, 15-tooth #25-chain sprocket, module-2 rack segment) | CADSF-1134 |
| `toys-games` | dice, chess sets, toy cars, fidget spinners, yoyos, frisbees, building bricks, jigsaw puzzles, figurines, marble runs, meeples and the EN71-1/ASTM F963/16 CFR 1501 choking-hazard/drop/edge/bite safety standards a toy or game piece is held to | 19 / 57 / 57 | 3 (16mm die with engraved pips, 2x4 brick-compatible block, revolved chess pawn) | CADSF-1135 |
| `garden-outdoor` | nursery pots, planters, birdhouses, bird feeders, watering cans, mailboxes, hose/sprinkler threads, raised beds, post caps, trellises and the UV/freeze-thaw/drop/water-tightness/wind-load tests an outdoor part is held to | 17 / 45 / 45 | 3 (tapered nursery planter with drainage holes, birdhouse box, 4x4 post cap) | CADSF-1138 |
| `jewellery-wearables` | rings, bangles, bracelets, earrings, pendants, watch cases and glasses — ring-size/band-width dimensions, comfort-fit and prong-setting rules, casting/DMLS processes, hypoallergenic materials and the wear/retention/drop tests a jewellery or wearable part is held to | 18 / 50 / 51 | 3 (plain wedding band, pendant tag with bail, watch bezel ring) | CADSF-1139 |
| `desktop-robots` | desk humanoids/companion robots, STS3215-class smart servos, dev-board eye/camera/speaker cutouts, wheeled rover chassis, quadrupeds and the drop/tip-over/pinch-point tests and ISO 13482/IEC 60335-1 stability standards a small hobby robot is held to | 18 / 43 / 43 | 3 (STS3215 servo mounting bracket, round robot head with eye cutout, two-wheel rover chassis plate) | CADSF-1140 |
| `furniture-construction` | the construction vocabulary of furniture — rail, stretcher, splat, apron, shell, star base, cantilever, lamination, tenon, mortise, dowel, cord seat, cane seat, half-lap, spacer, mount plate, swivel hub — each mapped to the op(s) that build it, plus standard member sections (leg 30–45 mm square, stretcher 20–25, light tube 12–16, veneer shell 8–10, moulded PU shell 25–40), joint-selection rules (leg↔rail mortise-tenon; shell↔frame screws through a mount plate; bent leg↔seat screws) and worked recipes for ten chair construction types. `cad_joint` / `cad_fastener` are marked *planned (CADSF-1370/1371)* with a today's-ops recipe beside each | 20 / 76 / 86 | 12 (2 joinery how-tos + 10 construction types) | CADSF-1381 |
| `turbomachinery` | first-stage HP turbine rotor blade proportions (aero-derivative and industrial-frame classes), fir-tree root and platform geometry, tip-clearance/rotor-speed practice, IN718/IN738LC properties at temperature, investment-casting castability limits (`ops/dfmRules.js`'s new `investment_casting` process) and the disc/blade tests and tolerances a turbogenerator rotor is held to | 16 / 42 / 44 | 3 (fir-tree root profile, platform+shank block, disc sector with a rim slot) | CADSF-1198 |
| `load-driven-detailing` | taking material out the way engineered parts do (LDD epic, CADSF-102461): gear/pulley/sprocket/idler/flywheel bodies (rim backup ratio m_B and AGMA 2001 rim factor K_B with its 0.5 to 1.2 range, web, hub, lightening-hole count and ligaments, web vs spokes, free gears with dog rings), castings (wall, draft, rib, boss, fillet, hot-spot and machined-pad rules for sand, permanent-mould and die-cast aluminium and iron) and fabricated frames (rail taper with moment, flanged lightening holes, Kt, gussets, fish plates, hole-to-weld). Every number is tagged `SRC:` (cited) or `EST:` (basis stated) in its `basis`. Entry ids are stable and prefixed `ldd-`; LDD [2], [7] and the V12 generators cite them | 19 / 50 / 54 | 2 (lightened m3 60-tooth gear body, tapered rail web with lightening holes) | CADSF-102462 |
| `composites` | fibre-ply manufacture: prepreg, fabric, adhesive and core data as `value.table` rows in the ply format `cad_design_knowledge {action:"laminate"}` resolves by row id (one row per condition: mean, hot/wet, design), autoclave, OOA, RTM, AFP and thermoplastic process chains, tooling and CTE, ply-drop, radius, drape, core-ramp, insert and bonded and bolted joint rules, trimming, NDT and coupon tests. Basis tags `SRC:` or `EST:` | 15 / 64 / 87 | 4 (open-hole coupon, ply-drop taper, core ramp, bolted lug) | CADSF-102479 |
| `motorsport` | how F1 and top-level racing make things: survival cell and FIA crash tests, surface-to-pattern-to-mould-to-ply-book part path, wings, wishbones and bonded fittings, titanium, printed and machined metallics, carbon-carbon brakes, and contrast with WEC, GT3, IndyCar, Formula E and FSAE. Regulation figures state their year and issue. Basis tags `SRC:` or `EST:` | 15 / 63 / 74 | 4 (wishbone end insert, disc cooling-hole plate, gurney strip, clevis) | CADSF-3370 |
| `race-engines` | pistons, rods, cranks, blocks and heads, liners and bore finish, valvetrain, forced induction, exhausts, dry sump, finishes, published series engine figures, F1 2026 power-unit rules and the dyno and crack tests. References `power-transmission` and `automotive` rather than copying them. Basis tags `SRC:` or `EST:` | 15 / 67 / 89 | 4 (wet liner, piston blank, spring retainer, valve blank) | CADSF-3371 |
| `battery-systems` | cell formats and swelling, tab and busbar joining, module and pack structure, cold plates and gap filler, propagation barriers and venting, HV creepage and clearance, UN 38.3, R100, GB 38031, UL 2580 tests, and motorsport energy stores. Check HV spacing against the current standard before relying on it. Basis tags `SRC:` or `EST:` | 15 / 70 / 89 | 4 (21700 holder, busbar, module end plate, cold plate) | CADSF-3372 |

## One pack, one sector

```
data/dfm/packs/furniture.json
```

```json
{
  "$schema": "nativecad-dfm-pack/1",
  "id": "furniture",
  "title": "Furniture — desks, chairs, tables, shelving, cabinets",
  "sector": "furniture",
  "version": "2026-09-03",
  "summary": "Ergonomic and regulatory dimensions, joinery, materials and the BIFMA/EN tests a piece of furniture is held to.",
  "aliases": ["desk", "chair", "table", "shelf", "cabinet", "office furniture"],
  "sources": [
    { "id": "bifma-x5.1", "title": "ANSI/BIFMA X5.1-2017 General-Purpose Office Chairs", "url": "https://www.bifma.org/...", "accessed": "2026-09-03" }
  ],
  "entries": [ ...see below... ]
}
```

| Field | Rule |
|---|---|
| `id` | lowercase kebab, equals the file name, unique across packs |
| `sector` | the same word; a pack IS a sector (sub-sectors go in `applies` / `tags`) |
| `aliases` | the words a user says that should route to this pack — the MCP `search` matches on them. **Unique across packs** (ids and sectors included): the build refuses a word two packs claim, because the loader can only route it to one. Prefer the specific form (`sheet metal enclosure`) over the shared word (`enclosure`) |
| `sources` | every source an entry cites; `id` unique in the pack, `url` optional but strongly preferred, `accessed` YYYY-MM-DD |
| `entries` | ≥ 40 for a sector pack; see tier minimums |

## One entry, one fact

```json
{
  "id": "seat-height",
  "kind": "dimension",
  "tier": 1,
  "title": "Task chair seat height (adjustable range)",
  "summary": "Adjustable seat height should span at least 380–510 mm above the floor (popliteal height of the 5th–95th percentile adult, ANSI/HFES 100 and BIFMA G1); a fixed-height chair sits at 430–460 mm.",
  "applies": ["task chair", "office chair", "fixed-height chair"],
  "value": { "min": 380, "max": 510, "typical": 450, "unit": "mm" },
  "basis": "Popliteal height 5th–95th percentile, seated, shod",
  "sources": ["bifma-g1", "hfes-100"],
  "tags": ["ergonomics", "seating"]
}
```

| Field | Rule |
|---|---|
| `id` | lowercase kebab, unique in the pack |
| `kind` | `dimension` \| `rule` \| `material` \| `process` \| `feature` \| `fastener` \| `tolerance` \| `test` \| `standard` \| `recipe` \| `note` |
| `tier` | `1` core, `2` standard, `3` full — see *Sizes* |
| `title` | ≤ 90 chars, a noun phrase |
| `summary` | ≤ 280 chars. **Contains the number.** An agent that reads only the summary must be able to act |
| `applies` | product/sub-sector words; an empty list means "the whole sector" |
| `value` | optional but expected on `dimension` / `rule` / `tolerance` / `fastener`: `{min,max,typical,unit}` (any subset, ≥ 1 of min/max/typical) \| `{value,unit}` \| `{options:[...]}` \| `{table:[{...}]}` for small tables |
| `unit` | `mm` `deg` `N` `kg` `g` `MPa` `GPa` `g/cm3` `um` `ratio` `%` `count` `Nm` `C` `mm/s` `Hz` `V` `W` `L` `h` `cycles` `in` — inch-published numbers stay in `in` (the CADSF-633 rule: a reviewer reads the digits the source printed) |
| `basis` | one line: WHY the number is what it is |
| `sources` | ≥ 1 for `dimension` / `rule` / `tolerance` / `test` / `standard` / `fastener`; every id must exist in `pack.sources` |
| `tags` | free words for search |
| `detail` | optional, tier ≥ 2 only, ≤ 1200 chars — the paragraph the summary compressed |
| `check` | optional: `{ "process": "<dfmRules pack>", "rule": "<rule code>", "params": {...} }` — when the fact is measurable by `cad_dfm_check`, say so; the agent can then verify rather than trust |
| `recipe` | required on `kind: recipe`: `{ "prompt": "what a user says", "steps": [ { "tool": "cad_box", "args": {...}, "note": "..." }, ... ], "expect": { "volume": ..., "faceCount": ... } }`. Tool names and argument shapes must be real (`docs/mcp-tools.json`); mm and radians; every step buildable on the current kernel — run it before you commit it |

### Kinds, and what each is for

- **dimension** — a size the product must have (seat height, key pitch, rack width). Value with min/max/typical.
- **rule** — a constraint on the geometry (hole ≥ 2 × wall from an edge, draft ≥ 1°, rib ≤ 60 % of wall). Prefer a `check` when dfmRules can measure it.
- **material** — what things are made of and why (6061-T6 for a bracket, PC for a housing that must pass UL 94 V-0). `value` may carry density / modulus / yield in a `table`.
- **process** — how the sector makes it and the geometry that process imposes (die-cast → draft + wall; laser-cut sheet → kerf + min hole).
- **feature** — a named feature and its conventions (screw boss, snap fit, living hinge, limber hole, cable gland boss) with the numbers.
- **fastener** — screws, inserts, pins, clips: sizes, hole conventions, edge distances.
- **tolerance** — what the sector expects and what the process gives.
- **test** — *things people test*: the test's name, the standard, the load/cycles/height/duration, and **what it demands of the geometry** ("1.2 m drop on corners → ≥ 2 mm corner radius, no unsupported wall > 40 mm").
- **standard** — the standard itself, one entry: what it covers, the clauses that touch geometry.
- **recipe** — a worked text-to-CAD build for the sector's common product, as real tool calls.
- **note** — anything true and useful that is none of the above.

## Sizes

An entry's `tier` says which sizes carry it. The loader and the build emit:

| Size | Carries | Target bytes per sector | Meant for |
|---|---|---|---|
| `core` | tier 1 | ≤ 16 KB | the numbers an agent needs to start a bracket-grade model in this sector; loaded by default |
| `standard` | tiers 1–2 | ≤ 64 KB | a real design session — tables, tests, recipes |
| `full` | tiers 1–3 | unbounded | reference: edge cases, standards prose, `detail` paragraphs |

Tier minimums per sector pack (the gate enforces them): **tier 1 ≥ 15**,
**tier 2 ≥ 15**, and ≥ 3 `test`, ≥ 2 `recipe`, ≥ 3 `material` entries somewhere
in the pack. Cross-sector packs (`hardware`, `materials`, `standards-testing`)
are exempt from the recipe/material minimums.

Pick the tier by asking: *would an agent get the product wrong without this?*
Tier 1 yes; tier 2 it would get it worse; tier 3 it would not notice.

## Modular loading

A pack is a file; the index is a list. `loadPack(['furniture','hardware'],
{size:'core'})` reads two files and nothing else. Cross-sector facts live in
the three cross-sector packs and are *referenced* (`"see": "hardware/m3-clearance"`)
rather than copied, so the number lives in one place.

## Authoring rules that keep a pack honest

1. **Numbers come from a source, and the source is named.** No source → no
   number. A round number you are sure of still needs a basis line.
2. **Say the unit the source said.** Inch-published → `"unit": "in"`.
3. **A range beats a point.** `{min, max, typical}` when the sector has a range.
4. **The summary carries the number.** Prose without a number is a `note` —
   the build refuses any other kind whose summary has no digit.
5. **A recipe was run.** Its `expect` block is what the kernel returned.
6. **A test says what geometry it wants.** A test entry with no geometric
   implication is a `standard`.
7. **Don't restate dfmRules.** Process limits (min wall by process, draft
   floors) live in `ops/dfmRules.js`; a pack entry points at them with `check`.
8. **No vendor pricing, no marketing.** Facts about parts, not about shops.

## The API (`ops/designKnowledge.js`)

```js
const DK = require('./ops/designKnowledge');
DK.listPacks();                                   // [{id, title, sector, aliases, counts:{core,standard,full}, bytes:{...}}]
DK.loadPack('furniture', { size: 'core' });       // the pack with entries filtered to tier <= 1
DK.loadPacks(['furniture','hardware'], { size: 'standard' });
DK.search('seat height', { sectors: ['furniture'], size: 'standard', kinds: ['dimension'], limit: 10 });
DK.resolveSector('office chair');                 // 'furniture' (by id, sector or alias)
DK.SIZES;                                         // { core: 1, standard: 2, full: 3 }
```

`search` scores on title, summary, applies, tags and id (tokenised,
case-folded, prefix-matched) and returns `{pack, id, kind, tier, title,
summary, value, score}` rows — never `detail`, never the whole pack.

## Build

```
node tools/build_dfm_packs.js          # validate, write packs/index.js and dist/
node tools/build_dfm_packs.js --check  # validate only (what the test does)
```

`dist/index.json` lists every pack with entry counts and byte sizes per
size, plus `all.<size>.json` bundles for a consumer who wants one file.
