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, source-side validation, free-pad selectors, destination-pad reference outlines, and schematic power-port projection. 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 pad outlines, bounding boxes, or future pin-1 markers. The implemented subset supports source_pad_outline from inspected DUT pad geometry and destination_pad_outline from the inserted mate footprint pad geometry. Both modes use one expanded outline by default and optional multiple outlines via outline_count or double_outline. The outline follows the effective pad body for circular, obround, rectangular/square, octagonal/chamfered, and rounded-rectangle pads. For drilled free pads, source outline graphics use the hole body as the reference feature. clearance_mils is the visible gap from the 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": "altium_cruncher.mate.config.a0",
  "source": {
    "board": "path/to/cricket-node.PrjPcb",
    "project_context": "auto"
  },
  "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
      },
      "scope": "all",
      "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, with lower-numbered single-pin designators near the top of each group. The default sheet style is D. Single-pin mate symbols are rotated so the pin hotspot faces right, the visible designator is placed to the left, and the comment field is hidden by default. Wires extend right from each single-pin symbol and are normalized to a shared 100 mil grid length based on the longest net label in that group. Net labels use right-lower justification at the wire end. If the resolved source schematic uses a power symbol for the same net, the generated schematic emits a matching power port at the wire end instead of a net label. Multi-pin symbols still use the selected signal-pin orientation and will get richer connector-specific layout heuristics in 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