ThePirateRay/docs/research/rayforge-recipe-model-spike.md

4.7 KiB

Rayforge material-recipe model spike

  • Date: 2026-10-20
  • Rayforge commit: c28918c87f8273dd1d244f5a057addc192807fa5
  • Scope: offline recipe schema, matching, persistence and extension seams
  • Transport: none

Result

Rayforge already provides the main recipe mechanism needed by the MOPA workbench. A recipe is a YAML-backed preset that can target a machine, laser head, material, thickness range and operation type. Applied settings are filtered through the selected step type's allowlist, and individual values can be marked “leave unchanged”. This is a substantially better reuse point than a second PirateRay recipe engine.

The pinned laser-step contract includes power, speed, frequency in Hz and pulse width in ns. A synthetic recipe carrying those fields matched only when its machine, material, thickness and step context were complete. It rejected a wrong material and missing stock context. An unknown setting survived recipe storage but was excluded when applying values to the synthetic step.

Existing fit

The current model covers:

  • stable recipe identity, name and description;
  • machine and laser-head compatibility;
  • material and thickness compatibility;
  • operation/step-type compatibility;
  • setting-level apply/leave-unchanged behavior;
  • post-processing settings;
  • specificity-based recipe selection;
  • one user-editable YAML file per recipe;
  • forward-compatible unknown metadata through Recipe.extra.

Rayforge materials and recipes are separate concepts. Materials describe stock identity and appearance; recipes carry process settings and can refer to a material UID. That separation fits the PirateRay requirement that recipes are optional accelerators rather than mandatory material wizards.

PirateRay gaps

The source does not expose native, validated fields for:

  • evidence provenance;
  • approval or validation status;
  • source/profile revision;
  • lens compatibility;
  • correction-profile compatibility;
  • named personal, makerspace-shared or project collections.

Machine and head matching use identifiers, but those identifiers alone do not prove that a recipe is safe for a JPT source, mounted lens or correction file. The existing extra round-trip can preserve namespaced PirateRay metadata, but preservation is not validation and the stock Rayforge UI does not explain or enforce those fields.

Narrow implementation direction

Reuse Recipe, RecipeManager, the existing selector/editor and step allowlists. The smallest extension should define a versioned, namespaced PirateRay metadata block with explicit provenance and compatibility fields, then validate it before a recipe can receive a stronger label than “unverified”. Keep unknown or incomplete compatibility fail-closed for encoding and physical execution.

Do not fork the recipe schema merely to add collections. First test whether separate manager directories or a small library wrapper can provide personal and makerspace-shared views while retaining Rayforge's file-per-recipe format. Project-local portability remains a separate, unproven requirement.

The exact evidence required for “makerspace-approved” remains a product and safety decision for Kaz. This spike deliberately does not invent that policy.

Implemented offline metadata gate

The external no-device addon now contains a version-1 pirateray metadata validator. It requires non-empty provenance and exact matches for machine profile, source type, lens profile and correction-profile hash. Missing or mismatched values are rejected independently.

The only currently accepted status is unverified. The tempting makerspace-approved label is rejected until its evidence and review policy has been decided. Even successfully validated metadata returns encoding_allowed: false and hardware_use_allowed: false; this contract organizes evidence but grants no controller capability.

The synthetic public fixture and regression tests exercise the contract without using physical machine identifiers or settings.

Reproduce

Run against the pinned checkout with the isolated Rayforge Python environment:

python scripts/spike_rayforge_recipe_model.py <rayforge-checkout> `
  --output tests/fixtures/rayforge-recipe-model.json

Source anchors

  • rayforge/core/recipe.py: schema, matching, allowlisting and extra
  • rayforge/core/recipe_manager.py: YAML persistence and selection
  • rayforge/core/material.py: material identity and appearance
  • rayforge/core/material_library.py: material-library storage
  • rayforge/builtin_addons/rayforge-addon-laser/laser_essentials/steps/laser_step.py: laser recipe fields and Hz/ns contracts
  • rayforge/ui_gtk/doceditor/recipes/: existing editor and selector

No USB enumeration, controller command, motion, physical framing, arming or laser output occurred.