mate portable config design

Status

This document describes the implemented mate_config.a0 shape and the portable design direction. The command contract is mate.html, and the generated Altium MCO operation contract is mco.html. Current implementation covers config initialization, selector resolution, name-based library lookup, mate component placement, PCB labels, board outline/cutout graphics and regions, STEP artifact insertion, PCB designator arrangement, and source-side validation. Some future projection actions remain draft.

Goal

The current command name is mate, but the domain model is broader: create an output board that mates to an input board. The first feature-complete use case is cricket-node mated to node-test-array derived fixture parts. The config model should remain portable enough to map later to KiCad and a generic pcb_cruncher workflow, while the current MCO backend remains Altium-specific.

Vocabulary

Term Meaning
source, input, DUT The existing board being analyzed. For the first workflow this is cricket-node.
destination, output, mate The generated board that physically mates to the source board.
human config The human-authored or GUI-authored source of truth. It describes intent and should avoid derived facts.
resolved plan The planner's internal view after reading source board facts: coordinates, nets, sides, source geometry, selected objects, and projection actions.
MCO The derived, inspectable, Altium-specific operation script compiled from the human config and resolved plan.

Config Principles

Theory Of Operations

  1. mate writes an editable mate.a0.jsonc when no config exists.
  2. The user or future GUI edits the config to choose source objects, mate parts, graphics, labels, output paths, and artifacts.
  3. plan resolves selectors against the source project, resolves symbol and footprint names from libraries.roots, validates source-side and geometry rules, and compiles MCO.
  4. mate with an existing config executes the generated MCO to create the output board and supporting artifacts.
  5. The user opens the output project in Altium for visual inspection, then iterates on the config.

Source Object Classes

The cricket-node use case needs these source object classes to be explicit in the planner, even when the first config uses presets or designator patterns.

Class Resolved Facts First Use
component Designator, footprint, schematic linkage when available, side, center, pads, net names, pin/pad mapping. TP-style test pads, M-style mounts, future J/connector/header mating.
free pad or drill Location, size, hole size, plated state, layer/span, net name when resolvable. Cricket-node 2 mm NPTH alignment pins and other free pads.
board outline Closed outline geometry, origin relationship, arcs/lines when available. Mechanical reference graphics or output outline setup.
internal cutout Regions inside the outline, shape geometry, layer/object metadata. Mechanical reference graphics and optional actual output cutouts.

Projection Actions

Action Meaning
mate_component Place a different symbol/footprint that mates to the selected source object, such as a pogo pin for a source test pad. The public A0 form names symbol_name and footprint_name; the planner resolves concrete libraries from libraries.roots.
copy_source_footprint Project the source footprint 1:1 into the output. This supports .100 inch headers, shield-style boards, and early workflows without a curated mate library.
same_pad Project equivalent pads or drills without a full component abstraction.
reference_graphics Add mechanical or silkscreen reference geometry, such as source-pad outlines, bounding boxes, or future pin-1 markers. The current implemented subset supports source_pad_outline from inspected source pad geometry, with one expanded outline by default and optional multiple outlines via outline_count or double_outline. The outline follows the effective source-layer pad body for circular, obround, rectangular/square, octagonal/chamfered, and rounded-rectangle pads. clearance_mils is the visible gap from the source pad edge to the inside edge of the outline stroke, so zero clearance makes the outline touch the pad edge. Filled source-pad graphics are a planned reference mode but are not part of this subset.
label Add text labels near mate features or in arranged groups. Labels may be tied to source nets, source designators, or custom text.
breakout Add additional connectors wired to selected source nets, such as future Saleae-style 2x4 headers with generated net labels and text labels.
outline_or_cutout Project source board outline or internal cutouts as graphics, actual output cutouts, or both.
alignment_artifact Produce generated helper outputs such as a bottom-layer STEP artifact from pcb-layer-step.

Side And Origin Rules

Cricket-Node Feature-Complete Target

The first complete workflow should support cricket-node without requiring users to type resolved coordinates or net names. The config should select source objects, and the planner should resolve the facts needed to compile MCO.

Proposed Config Shape

This is the implemented public A0 shape used by the Cricket Node example. Some optional sections and future projection actions may still evolve after review.

{
  "schema": "wn.pcb_cruncher.mate_config.a0",
  "source": {
    "board": "path/to/cricket-node.PrjPcb",
    "pcbdoc": null
  },
  "output": {
    "backend": "altium",
    "output_dir": "output/cricket-node-mate",
    "project_name": "cricket_node_mate",
    "schematic_sheet_style": "D",
    "origin": "preserve_source",
    "board_outline": {
      "mode": "source_bounds_with_margin",
      "margin_mils": {
        "left": 500,
        "bottom": 500,
        "right": 3000,
        "top": 500
      }
    }
  },
  "libraries": {
    "roots": ["mating_parts"],
    "recursive": true
  },
  "validation": {
    "source_side": "infer_single_side",
    "allow_side_agnostic_through_hole": true
  },
  "projections": [
    {
      "id": "test_points",
      "source": {
        "object": "component",
        "designators": "TP*"
      },
      "actions": [
        {
          "kind": "mate_component",
          "symbol_name": "YZ209315103P-01",
          "footprint_name": "YZ209315103P-01",
          "designator_prefix": "TP",
          "signal_pad_designator": "1"
        },
        {
          "kind": "reference_graphics",
          "shape": "source_pad_outline",
          "layer": "MECHANICAL_1",
          "style": {
            "mode": "outline",
            "outline_count": 1,
            "clearance_mils": 10,
            "stroke_width_mils": 10
          }
        },
        {
          "kind": "label",
          "text": "source_net",
          "placement": {
            "side": "board_right",
            "offset_mils": [250, 250],
            "box_size_mils": [450, 70],
            "row_spacing_mils": 90,
            "column_spacing_mils": 80,
            "auto_width_padding_mils": 80
          }
        }
      ]
    },
    {
      "id": "mounts",
      "source": {
        "object": "component",
        "designators": "M1-4"
      },
      "actions": [
        {
          "kind": "mate_component",
          "symbol_name": "9774080360R",
          "footprint_name": "9774080360R-YIYUAN",
          "designator_prefix": "M"
        }
      ]
    },
    {
      "id": "alignment_pins",
      "source": {
        "object": "free_pad",
        "hole_size_mils": {"min": 75, "max": 85},
        "plated": false
      },
      "actions": [
        {
          "kind": "mate_component",
          "symbol_name": "H2184-05",
          "footprint_name": "H2184-05",
          "designator_prefix": "P",
          "signal_pad_designator": "1"
        },
        {"kind": "label", "text": "source_net"}
      ]
    }
  ],
  "pcb_designators": {
    "enabled": true,
    "placement": "above_component",
    "offset_mils": [0, 10],
    "width_factor": 0.6,
    "style": {
      "height_mils": 40,
      "layer": "TOP_OVERLAY",
      "font_kind": "truetype",
      "font_name": "Arial",
      "bold": true,
      "stroke_width_mils": 8
    }
  },
  "board_projection": {
    "outline": {
      "graphics": {
        "enabled": true,
        "layer": "TOP_OVERLAY",
        "stroke_width_mils": 8
      }
    },
    "cutouts": {
      "graphics": {
        "enabled": true,
        "layer": "MECHANICAL_1",
        "stroke_width_mils": 8
      },
      "actual_cutouts": true
    }
  },
  "artifacts": {
    "pcb_layer_step": {
      "enabled": true,
      "source_layer": "bottom",
      "z_mm": 0.0,
      "thickness_mm": 0.035,
      "include_board_outline": true,
      "board_outline": {
        "color": "#FFFF00",
        "cutout_color": "#FFFF00",
        "cutouts": true,
        "width_mm": 0.2,
        "fuse": true
      },
      "features": {
        "defaults": {"color": "#B87333"},
        "tracks": {"enabled": false, "color": "#B87333", "step_body_name": "tracks", "thickness_bias_mm": 0.0},
        "arcs": {"enabled": false, "color": "#B87333", "step_body_name": "arcs", "thickness_bias_mm": 0.0},
        "fills": {"enabled": false, "color": "#B87333", "step_body_name": "fills", "thickness_bias_mm": 0.0},
        "polygons": {"enabled": false, "color": "#7A8F2A", "step_body_name": "polygons", "thickness_bias_mm": 0.003},
        "regions": {"enabled": false, "color": "#7A8F2A", "step_body_name": "regions", "thickness_bias_mm": 0.003},
        "vias": {"enabled": false, "color": "#C08540", "step_body_name": "vias", "thickness_bias_mm": 0.006},
        "component_pads": {
          "mode": "matching_designators",
          "include_designators": ["TP*", "M*"],
          "color": "#B87333",
          "step_body_name": "component_pads",
          "thickness_bias_mm": 0.010,
          "highlight_rules": [
            {"designators": ["TP*"], "color": "red", "step_body_name": "test_points"}
          ]
        },
        "free_pads": {"enabled": false, "color": "#B87333", "step_body_name": "free_pads", "thickness_bias_mm": 0.010}
      },
      "drills": {
        "mode": "overlay",
        "selected_component_mode": "cut",
        "other_component_mode": "none",
        "free_pad_mode": "overlay",
        "via_mode": "inherit",
        "minimum_diameter_mm": 0.85,
        "shape": "ring",
        "color": "#666666",
        "plated_color": "#666666",
        "non_plated_color": "#00AEEF",
        "ring_width_mm": 0.12,
        "plated_ring_shape": "annulus",
        "overlay_thickness_mm": 0.001
      },
      "fuse_copper": false,
      "insert_in_output": {
        "enabled": true,
        "z_mm": 8.5,
        "layer": "MECHANICAL_13",
        "side": "TOP"
      },
      "highlights": [
        {"projection": "test_points", "color": "#FF0000"}
      ]
    }
  }
}

Init And GUI Behavior

Before a GUI exists, bare mate produces a commented config with useful selector presets and optional sections. Later, a GUI can render the source board SVG, show grouped source objects such as test points, debug pads, connectors, and mounts, and write the same config format after user selection.

Source selectors are local to each projection group. Component designators may be a wildcard, a compact range such as TP1-5, a comma-separated expression such as TP1-5, U12, or an explicit JSON array for machine-generated configs.

Projection actions own their output options. For example, two projection groups may both use label actions but choose different placement side, offsets, box sizes, and text style. Mate configs therefore do not use the legacy global pcb_labels block as the primary label contract. A label side of left or right places the label relative to the projected target, while board_left or board_right places labels in vertical columns inside the output board outline. Board-edge labels are grouped by projection id, falling back to source kind when no projection id is present. Each board-edge column gets a silkscreen text header using that group name. row_spacing_mils sets spacing within a column, column_spacing_mils sets spacing between columns, and auto_width_padding_mils is added to the longest rendered label estimate so every board-edge label box uses the same width. Board-edge labels and their headers are emitted after the generated feature union and are therefore not part of MATE_FEATURES.

Generated schematic placement is intentionally simple but collision-aware: mate symbols are placed on a coarse grid grouped by symbol type and sorted in natural designator order within each group, the default sheet style is D, schematic designators are centered just above their symbols, wires extend away from each symbol in the selected signal pin orientation, and schematic net labels sit along those wires with matching orientation. Wire length is estimated from the label text so it remains visible beneath the label, and the grid leaves room before the next symbol column. This keeps the first generated schematic reviewable while leaving connector-specific and breakout-specific schematic organization for later slices.

pcb_designators is a post-placement PCB text normalization block. The current implemented placement is above_component; it updates the generated component-owned designator text instead of adding duplicate loose text. The cricket-node default is Arial TrueType, 40 mil, bold, on top overlay.

Artifact highlights reference projection ids instead of duplicating source selectors. pcb-layer-step owns layer, local STEP Z, thickness, feature visibility, feature colors, STEP body names, and feature thickness bias. The generated mate JSONC template renders this artifact section with field-level comments following ADR-0007 because it mirrors the pcb-layer-step config contract. Output-board insertion owns the model-placement z_mm; for the Cricket Node example that value is 8.5 mm while the exported STEP uses local z_mm: 0.0. Since z_mm is the bottom extrusion plane, the generated artifact keeps the same local Z default as pcb-layer-step --init-config. The first example renders selected TP pads red and makes track and polygon visibility/color choices explicit.

Deferred Topics