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 andextrarayforge/core/recipe_manager.py: YAML persistence and selectionrayforge/core/material.py: material identity and appearancerayforge/core/material_library.py: material-library storagerayforge/builtin_addons/rayforge-addon-laser/laser_essentials/steps/laser_step.py: laser recipe fields and Hz/ns contractsrayforge/ui_gtk/doceditor/recipes/: existing editor and selector
No USB enumeration, controller command, motion, physical framing, arming or laser output occurred.