evidence: analyze LightBurn device exports
This commit is contained in:
parent
ceb70be30e
commit
202e756071
8 changed files with 239 additions and 60 deletions
32
README.md
32
README.md
|
|
@ -25,15 +25,21 @@ Phase 0 has established a reproducible evidence and research baseline:
|
||||||
correction data, material libraries, and relevant configuration files;
|
correction data, material libraries, and relevant configuration files;
|
||||||
- the physical controller has been passively identified by Windows as
|
- the physical controller has been passively identified by Windows as
|
||||||
`USBLMCV4`, USB `9588:9899`, with device revision descriptor `0005`;
|
`USBLMCV4`, USB `9588:9899`, with device revision descriptor `0005`;
|
||||||
|
- LightBurn `2.1.03` exports now confirm the JPT `JCZFiber`/`LibUSB` profile,
|
||||||
|
110 x 110 mm work area, Q-pulse-width support, and the exact serialized
|
||||||
|
setting name `QPulseWidth`;
|
||||||
|
- the Eduard X1550 export confirms a Ruida/Serial profile and 1500 x 1000 mm
|
||||||
|
work area;
|
||||||
- the development computer has no compatible controller driver installed;
|
- the development computer has no compatible controller driver installed;
|
||||||
- no USB endpoint has been opened and no controller command, galvo movement,
|
- no USB endpoint has been opened and no controller command, galvo movement,
|
||||||
framing, marking, or laser output has occurred;
|
framing, marking, or laser output has occurred;
|
||||||
- the public tests, provenance checks, leak guard, and clean-clone validation
|
- the public tests, provenance checks, leak guard, and clean-clone validation
|
||||||
pass.
|
pass.
|
||||||
|
|
||||||
Phase 0 remains open while we collect the LightBurn bundle, preferences,
|
Phase 0 remains open while we collect known-working LightBurn projects, device
|
||||||
known-working projects, device screenshots, machine photos, and operator notes
|
screenshots, the closed-application preferences folder, machine photos, and
|
||||||
directly from the actual control computer.
|
operator notes directly from the actual control computer. The bundle and
|
||||||
|
exported preferences are already preserved and analyzed.
|
||||||
|
|
||||||
## The important discovery
|
## The important discovery
|
||||||
|
|
||||||
|
|
@ -55,16 +61,17 @@ BalorMK. This remains a proposed decision until the offline proofs in
|
||||||
|
|
||||||
## Next steps
|
## Next steps
|
||||||
|
|
||||||
The next work is deliberately offline and hardware-free:
|
The initial offline architecture spikes have passed. The next work remains
|
||||||
|
hardware-free:
|
||||||
|
|
||||||
1. run a synthetic MOPA job through MeerK40t's mock controller;
|
1. collect known-working `.lbrn2` projects and the remaining screenshots,
|
||||||
2. prove that an external Rayforge addon can register a binary no-device
|
photos, preferences folder and operator notes;
|
||||||
driver on Windows;
|
2. extend the synthetic import tests with the now-observed `QPulseWidth`
|
||||||
3. translate a small Rayforge operation stream into a deterministic JCZ trace
|
evidence, without assuming its `.lbrn2` representation;
|
||||||
and compare it with BalorMK;
|
3. define the minimum Rayforge JCZ device-profile/import extension and finish
|
||||||
4. test Rayforge's existing LightBurn import against galvo/MOPA fixtures;
|
controller-list buffering and safe state ordering offline;
|
||||||
5. accept, revise, or reject the proposed reuse architecture from evidence;
|
4. accept, revise, or reject the proposed reuse architecture from evidence;
|
||||||
6. write and review a separate hardware protocol before any live controller
|
5. write and review a separate hardware protocol before any live controller
|
||||||
communication.
|
communication.
|
||||||
|
|
||||||
An independent desktop application is the fallback only if both existing
|
An independent desktop application is the fallback only if both existing
|
||||||
|
|
@ -86,6 +93,7 @@ project workspace or development destination.
|
||||||
- [Open-source reuse landscape](docs/research/open-source-landscape.md)
|
- [Open-source reuse landscape](docs/research/open-source-landscape.md)
|
||||||
- [Proposed Rayforge/BalorMK reuse decision](docs/adr/0002-reuse-rayforge-and-balormk.md)
|
- [Proposed Rayforge/BalorMK reuse decision](docs/adr/0002-reuse-rayforge-and-balormk.md)
|
||||||
- [Live USB enumeration](docs/research/live-usb-enumeration-2026-10-17.md)
|
- [Live USB enumeration](docs/research/live-usb-enumeration-2026-10-17.md)
|
||||||
|
- [LightBurn device-export analysis](docs/research/lightburn-device-exports-2026-10-19.md)
|
||||||
- [Sanitized machine profile](docs/research/machine-profile.yaml)
|
- [Sanitized machine profile](docs/research/machine-profile.yaml)
|
||||||
- [110/300 configuration comparison](docs/research/config-comparison.md)
|
- [110/300 configuration comparison](docs/research/config-comparison.md)
|
||||||
- [Data handling policy](docs/data-handling.md)
|
- [Data handling policy](docs/data-handling.md)
|
||||||
|
|
|
||||||
114
docs/research/lightburn-device-exports-2026-10-19.md
Normal file
114
docs/research/lightburn-device-exports-2026-10-19.md
Normal file
|
|
@ -0,0 +1,114 @@
|
||||||
|
# LightBurn device-export analysis
|
||||||
|
|
||||||
|
- Date: 2026-10-19
|
||||||
|
- Scope: four user-provided LightBurn exports, analyzed offline
|
||||||
|
- LightBurn version recorded by all three bundle manifests: `2.1.03`
|
||||||
|
- Safety boundary: no executable, driver, USB endpoint or machine command was
|
||||||
|
used
|
||||||
|
|
||||||
|
## Evidence
|
||||||
|
|
||||||
|
Raw exports remain in PrivateStash. This public record contains hashes,
|
||||||
|
structure and independently derived findings only.
|
||||||
|
|
||||||
|
| Artifact ID | Size | Role |
|
||||||
|
| --- | ---: | --- |
|
||||||
|
| `sha256-e16fdb0aa7c374c4c94d` | 20,309 bytes | Complete bundle containing three device profiles, preferences and libraries |
|
||||||
|
| `sha256-fc6cf52f4ef815dd5037` | 5,720 bytes | Eduard device bundle |
|
||||||
|
| `sha256-88c762adcb8e9693c913` | 97,356 bytes | Exported LightBurn preferences |
|
||||||
|
| `sha256-d422e9886e29ed666c07` | 8,798 bytes | JPT MOPA device bundle |
|
||||||
|
|
||||||
|
Every digest and size is recorded in
|
||||||
|
[`evidence/public-lightburn-exports.jsonl`](../../evidence/public-lightburn-exports.jsonl).
|
||||||
|
Private paths, device GUIDs and local account data are intentionally omitted.
|
||||||
|
|
||||||
|
## Bundle structure
|
||||||
|
|
||||||
|
The complete bundle has eight entries: preferences, material-test presets,
|
||||||
|
three LightBurn device profiles, two material libraries and a bundle manifest.
|
||||||
|
Each device-specific bundle contains preferences, one device profile and a
|
||||||
|
manifest. All manifests declare bundle format `1.0` and LightBurn `2.1.03`.
|
||||||
|
|
||||||
|
## Device findings
|
||||||
|
|
||||||
|
| Display name | LightBurn backend | Connection | Work area | Attribution |
|
||||||
|
| --- | --- | --- | ---: | --- |
|
||||||
|
| `100 JPT E2 MOPA` | `JCZFiber` | `LibUSB` | 110 × 110 mm | Focus machine |
|
||||||
|
| `Eduard X1550` | `Ruida` | `Serial` | 1500 × 1000 mm | Makerspace CO2 machine |
|
||||||
|
| `Ruida 644XS` | `Ruida` | `CDM` | 500 × 300 mm | Unassigned; physical machine unknown |
|
||||||
|
|
||||||
|
The preferences contain four device records because the unassigned Ruida
|
||||||
|
profile occurs twice. This is not evidence for a fourth physical machine, and
|
||||||
|
the 500 × 300 mm profile must not be attributed to the Bodor or any other
|
||||||
|
machine without independent confirmation.
|
||||||
|
|
||||||
|
The JPT profile additionally records:
|
||||||
|
|
||||||
|
- a numeric laser type of `1` and fiber type of `3`;
|
||||||
|
- enabled Q-pulse-width control;
|
||||||
|
- profile frequency bounds stored as `1` and `4000`;
|
||||||
|
- `RequireFrameBeforeStart` enabled;
|
||||||
|
- 60 cut-list entries.
|
||||||
|
|
||||||
|
Numeric enums are preserved as observations. Their semantic labels are not
|
||||||
|
guessed from the numbers alone.
|
||||||
|
|
||||||
|
## MOPA process-setting evidence
|
||||||
|
|
||||||
|
Across the 60 exported cut-list entries:
|
||||||
|
|
||||||
|
- 35 contain `frequency`;
|
||||||
|
- 25 contain `QPulseWidth`;
|
||||||
|
- all 25 pulse-width entries also contain frequency;
|
||||||
|
- observed raw frequency values range from 30,000 to 1,000,000;
|
||||||
|
- observed `QPulseWidth` values range from 2 to 180.
|
||||||
|
|
||||||
|
LightBurn's official galvo cut-setting documentation presents frequency in
|
||||||
|
kHz and Q-Pulse Width in nanoseconds. The larger integers stored by the export
|
||||||
|
show that the serialized representation cannot simply be copied into a UI
|
||||||
|
field without an explicit conversion contract. The exact field name and unit
|
||||||
|
are now evidenced for a device-library export, but the representation inside
|
||||||
|
a `.lbrn2` project remains unconfirmed.
|
||||||
|
|
||||||
|
These observed recipe values and profile fields are **not certified hardware
|
||||||
|
limits or safe operating parameters**. They must not be used to probe the
|
||||||
|
machine. LightBurn likewise warns that incorrect galvo source settings can
|
||||||
|
damage a laser.
|
||||||
|
|
||||||
|
Sources:
|
||||||
|
|
||||||
|
- [LightBurn galvo-specific cut settings](https://docs.lightburnsoftware.com/2.2/Reference/CutSettingsEditor/GalvoSpecificCutSettings/)
|
||||||
|
- [LightBurn galvo source settings](https://docs.lightburnsoftware.com/latest/Reference/DeviceSettings/GalvoPorts/)
|
||||||
|
|
||||||
|
## Reuse impact
|
||||||
|
|
||||||
|
Rayforge's current LightBurn **project** importer retains raw frequency
|
||||||
|
metadata but maps neither frequency nor pulse width into workflow settings.
|
||||||
|
Its separate LightBurn **device** importer recognizes common profile fields,
|
||||||
|
but its driver map does not cover this observed `LibUSB`/`JCZFiber` pairing
|
||||||
|
and it does not map the JPT-specific settings or cut list.
|
||||||
|
|
||||||
|
The narrowest useful implementation is therefore an extension rather than a
|
||||||
|
new general parser:
|
||||||
|
|
||||||
|
1. add evidence-backed JCZ device-profile recognition;
|
||||||
|
2. preserve source units and raw values at the import boundary;
|
||||||
|
3. map frequency and `QPulseWidth` only after a real `.lbrn2` fixture confirms
|
||||||
|
project serialization;
|
||||||
|
4. validate imported values against a separately verified machine profile;
|
||||||
|
5. fail closed when units, profile identity or ranges are unknown.
|
||||||
|
|
||||||
|
## Remaining collection gaps
|
||||||
|
|
||||||
|
The exports settle the exact LightBurn release and the two named device
|
||||||
|
profiles. Phase 0 still needs:
|
||||||
|
|
||||||
|
- two or three known-working `.lbrn2` projects, especially a MOPA/hatch job;
|
||||||
|
- Device Settings and device-list screenshots;
|
||||||
|
- the closed-application LightBurn preferences directory;
|
||||||
|
- exterior machine, source, controller and installed-lens photographs;
|
||||||
|
- mounted-lens, connection, startup and interlock notes;
|
||||||
|
- the stock driver's identity and version on the control computer.
|
||||||
|
|
||||||
|
An About screenshot is still useful as visual corroboration, but the bundle
|
||||||
|
manifests already establish version `2.1.03`.
|
||||||
|
|
@ -19,9 +19,14 @@ optics:
|
||||||
- width: 300
|
- width: 300
|
||||||
height: 300
|
height: 300
|
||||||
lightburn:
|
lightburn:
|
||||||
version: null
|
version: 2.1.03
|
||||||
build: null
|
build: null
|
||||||
status: pending-collection
|
device_name: 100 JPT E2 MOPA
|
||||||
|
backend: JCZFiber
|
||||||
|
connection: LibUSB
|
||||||
|
q_pulse_width_enabled: true
|
||||||
|
require_frame_before_start: true
|
||||||
|
status: bundle-export-observed
|
||||||
usb:
|
usb:
|
||||||
vid: "9588"
|
vid: "9588"
|
||||||
pid: "9899"
|
pid: "9899"
|
||||||
|
|
@ -45,8 +50,16 @@ evidence:
|
||||||
- artifact_id: sha256-ebfe631958b9522533ff
|
- artifact_id: sha256-ebfe631958b9522533ff
|
||||||
sha256: ebfe631958b9522533ffb1e78c8961073e3549039053ea0d56e4c82cfe8bff83
|
sha256: ebfe631958b9522533ffb1e78c8961073e3549039053ea0d56e4c82cfe8bff83
|
||||||
role: jcz-windows-driver-metadata
|
role: jcz-windows-driver-metadata
|
||||||
|
- artifact_id: sha256-d422e9886e29ed666c07
|
||||||
|
sha256: d422e9886e29ed666c077a0e7bab9a6c3d53fc938365b7b773d79c529b55c0f0
|
||||||
|
role: lightburn-jpt-device-bundle
|
||||||
|
- artifact_id: sha256-88c762adcb8e9693c913
|
||||||
|
sha256: 88c762adcb8e9693c9132473a9d90c69eaf768b96f12e8af71e89adfb10b4cfa
|
||||||
|
role: lightburn-preferences-export
|
||||||
notes:
|
notes:
|
||||||
- No complete serial numbers or private source locators are stored here.
|
- No complete serial numbers or private source locators are stored here.
|
||||||
- Incorrect galvo or source configuration can damage hardware; values are not inferred by trial and error.
|
- Incorrect galvo or source configuration can damage hardware; values are not inferred by trial and error.
|
||||||
- USB identity was confirmed by passive Windows PnP enumeration on 2026-10-17; no device endpoint was opened.
|
- USB identity was confirmed by passive Windows PnP enumeration on 2026-10-17; no device endpoint was opened.
|
||||||
- USB revision 0005 is a descriptor value, not a proven board or firmware version.
|
- USB revision 0005 is a descriptor value, not a proven board or firmware version.
|
||||||
|
- LightBurn bundle manifests establish version 2.1.03 but do not expose a separate build identifier.
|
||||||
|
- Exported recipe values are observations, not certified hardware limits or safe operating parameters.
|
||||||
|
|
|
||||||
|
|
@ -14,9 +14,12 @@ speed and one pass. LightBurn's observed `frequency` and
|
||||||
|
|
||||||
However, the importer does not map frequency into the workflow layer settings.
|
However, the importer does not map frequency into the workflow layer settings.
|
||||||
It maps only power, speed and passes from this fixture. The inspected Rayforge
|
It maps only power, speed and passes from this fixture. The inspected Rayforge
|
||||||
LightBurn fixtures and importer contain no evidence-backed mapping for a MOPA
|
LightBurn project fixtures and importer contain no evidence-backed mapping for
|
||||||
pulse-width field. Consequently, the imported job is explicitly classified as
|
a MOPA pulse-width field. A later private LightBurn device-library export
|
||||||
unsafe for JCZ encoding rather than being completed with a guessed value.
|
establishes the field name `QPulseWidth` and its nanosecond UI contract, but it
|
||||||
|
does not establish how that value is serialized in a `.lbrn2` project.
|
||||||
|
Consequently, the imported job is explicitly classified as unsafe for JCZ
|
||||||
|
encoding rather than being completed with a guessed mapping.
|
||||||
|
|
||||||
Two runs produced identical output with SHA-256
|
Two runs produced identical output with SHA-256
|
||||||
`9ebce7b5b3388abfeed024e25f8f46001260bf814da19808bfc83fb6554fc26e`.
|
`9ebce7b5b3388abfeed024e25f8f46001260bf814da19808bfc83fb6554fc26e`.
|
||||||
|
|
@ -28,8 +31,12 @@ The golden result is `tests/fixtures/rayforge-lightburn-mopa-import.json`.
|
||||||
`overrideFrequency` elements.
|
`overrideFrequency` elements.
|
||||||
- **Observed:** generic parsing retains these elements in source metadata.
|
- **Observed:** generic parsing retains these elements in source metadata.
|
||||||
- **Observed:** `_build_step_config` does not map frequency or pulse width.
|
- **Observed:** `_build_step_config` does not map frequency or pulse width.
|
||||||
- **Unknown:** the exact LightBurn field and unit for JPT MOPA pulse width in a
|
- **Observed after this spike:** a LightBurn `2.1.03` device-library export
|
||||||
known-working galvo project.
|
uses `QPulseWidth`; official LightBurn documentation defines Q-pulse width
|
||||||
|
in nanoseconds. See the
|
||||||
|
[device-export analysis](lightburn-device-exports-2026-10-19.md).
|
||||||
|
- **Unknown:** the exact `QPulseWidth` representation and omission/default
|
||||||
|
behavior in a known-working galvo `.lbrn2` project.
|
||||||
- **Not inferred:** no pulse-width tag, unit, default or machine limit was
|
- **Not inferred:** no pulse-width tag, unit, default or machine limit was
|
||||||
invented for the public fixture.
|
invented for the public fixture.
|
||||||
|
|
||||||
|
|
@ -38,9 +45,8 @@ The golden result is `tests/fixtures/rayforge-lightburn-mopa-import.json`.
|
||||||
Rayforge's existing LightBurn importer is useful for ordinary vector geometry
|
Rayforge's existing LightBurn importer is useful for ordinary vector geometry
|
||||||
and common process settings, but it does not yet satisfy M1's MOPA parameter
|
and common process settings, but it does not yet satisfy M1's MOPA parameter
|
||||||
survival requirement. The narrowest likely extension is an importer mapping
|
survival requirement. The narrowest likely extension is an importer mapping
|
||||||
for frequency plus a separately evidenced pulse-width field, followed by an
|
for frequency plus `QPulseWidth`, followed by an explicit unit conversion and
|
||||||
explicit validation gate. A private known-working LightBurn project is still
|
validation gate. A private known-working LightBurn project is still needed to
|
||||||
needed to establish the pulse-width representation before implementing that
|
establish project serialization before implementing that mapping.
|
||||||
mapping.
|
|
||||||
|
|
||||||
No USB enumeration, controller command, motion or emission was attempted.
|
No USB enumeration, controller command, motion or emission was attempted.
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
# Product and research roadmap
|
# Product and research roadmap
|
||||||
|
|
||||||
Last updated: 2026-10-18
|
Last updated: 2026-10-19
|
||||||
|
|
||||||
## Destination
|
## Destination
|
||||||
|
|
||||||
|
|
@ -46,7 +46,8 @@ evidence.
|
||||||
The collected installer snapshot establishes:
|
The collected installer snapshot establishes:
|
||||||
|
|
||||||
- the JCZ/EZCAD2 controller and `Lmcv2u` driver family;
|
- the JCZ/EZCAD2 controller and `Lmcv2u` driver family;
|
||||||
- vendor-declared USB VID/PID values, pending live confirmation;
|
- vendor-declared USB VID/PID values, subsequently confirmed by passive live
|
||||||
|
Windows enumeration;
|
||||||
- known-good 110 mm and 300 mm configuration trees;
|
- known-good 110 mm and 300 mm configuration trees;
|
||||||
- exact hashes for the opaque, lens-specific `markcfg7` profiles;
|
- exact hashes for the opaque, lens-specific `markcfg7` profiles;
|
||||||
- a shared correction file and observable workspace differences;
|
- a shared correction file and observable workspace differences;
|
||||||
|
|
@ -60,7 +61,13 @@ It does **not** yet establish:
|
||||||
- which values are controller settings versus laser-source settings;
|
- which values are controller settings versus laser-source settings;
|
||||||
- status, interlock, error, abort, and recovery behavior;
|
- status, interlock, error, abort, and recovery behavior;
|
||||||
- whether an apparently harmless query can move a galvo or arm emission;
|
- whether an apparently harmless query can move a galvo or arm emission;
|
||||||
- the exact LightBurn version and known-working LightBurn device profile.
|
- how a known-working `.lbrn2` project serializes JPT frequency and
|
||||||
|
`QPulseWidth` settings.
|
||||||
|
|
||||||
|
The later LightBurn export collection now establishes version `2.1.03`, a
|
||||||
|
110 x 110 mm `JCZFiber`/`LibUSB` JPT profile, and the `QPulseWidth` device
|
||||||
|
library field. See the
|
||||||
|
[device-export analysis](research/lightburn-device-exports-2026-10-19.md).
|
||||||
|
|
||||||
Consequently, treating a vendor DLL or opaque profile as a callable black box
|
Consequently, treating a vendor DLL or opaque profile as a callable black box
|
||||||
would be premature and would make the safety boundary impossible to audit.
|
would be premature and would make the safety boundary impossible to audit.
|
||||||
|
|
@ -147,10 +154,11 @@ controller-safe state ordering remains an explicit evidence gap.
|
||||||
[The synthetic LightBurn MOPA import spike](research/rayforge-lightburn-mopa-import-spike.md)
|
[The synthetic LightBurn MOPA import spike](research/rayforge-lightburn-mopa-import-spike.md)
|
||||||
confirms that Rayforge preserves geometry, power, speed and passes and retains
|
confirms that Rayforge preserves geometry, power, speed and passes and retains
|
||||||
an observed LightBurn frequency value in raw source metadata. Frequency is not
|
an observed LightBurn frequency value in raw source metadata. Frequency is not
|
||||||
mapped into workflow settings, and no evidence-backed pulse-width field was
|
mapped into workflow settings. A later real device export identifies
|
||||||
found, so the job deliberately fails the JCZ encoding gate. A private
|
`QPulseWidth` and its nanosecond UI contract, but project serialization remains
|
||||||
known-working galvo fixture is required before implementing the missing MOPA
|
unknown, so the job still deliberately fails the JCZ encoding gate. A private
|
||||||
mapping.
|
known-working `.lbrn2` fixture is required before implementing the missing
|
||||||
|
MOPA mapping.
|
||||||
|
|
||||||
The architecture decision remains proposed until these spikes produce
|
The architecture decision remains proposed until these spikes produce
|
||||||
evidence. An independent app requires a documented gap analysis showing why
|
evidence. An independent app requires a documented gap analysis showing why
|
||||||
|
|
@ -251,17 +259,22 @@ imply compatible safety or control behavior on either CO2 machine.
|
||||||
|
|
||||||
The next work package should be small enough to review in a few commits:
|
The next work package should be small enough to review in a few commits:
|
||||||
|
|
||||||
1. collect the pending LightBurn data from the control PC as one local archive;
|
1. collect two or three known-working `.lbrn2` projects plus the remaining
|
||||||
2. run the stock MeerK40t mock-controller evaluation;
|
device screenshots, preferences folder, photos and operator notes;
|
||||||
3. prove the Rayforge external-addon and binary-driver registration seam;
|
2. add a sanitized synthetic JCZ `.lbdev` fixture and characterize the exact
|
||||||
4. build one no-I/O Rayforge-to-JCZ encoder spike and golden trace comparison;
|
gaps in Rayforge's device importer;
|
||||||
5. test Rayforge's existing LightBurn import against galvo/MOPA fixtures;
|
3. implement and test the smallest evidence-backed JCZ profile-import seam,
|
||||||
6. accept, amend or reject ADR 0002 from the results;
|
keeping project `QPulseWidth` mapping gated until a real project confirms
|
||||||
7. separately produce a written M3 hardware-research protocol before any USB
|
its serialization;
|
||||||
access or controller command.
|
4. extend the offline JCZ encoder from semantic records to controller-list
|
||||||
|
buffering and explicit safe state ordering, still without transport;
|
||||||
|
5. exercise cancellation/recovery and the graphical workflow against mock
|
||||||
|
backends, then accept, amend or reject ADR 0002;
|
||||||
|
6. separately produce a written M3 hardware-research protocol before any USB
|
||||||
|
endpoint access or controller command.
|
||||||
|
|
||||||
Items 2–6 can proceed while item 1 is pending. Hardware work cannot proceed
|
Hardware work cannot proceed until item 6 is reviewed and the physical setup
|
||||||
until item 7 is reviewed and the physical setup is ready.
|
is ready.
|
||||||
|
|
||||||
## Decision rules
|
## Decision rules
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
# Phase 0 status
|
# Phase 0 status
|
||||||
|
|
||||||
Last updated: 2026-10-17
|
Last updated: 2026-10-19
|
||||||
|
|
||||||
## Completed
|
## Completed
|
||||||
|
|
||||||
|
|
@ -22,29 +22,36 @@ Last updated: 2026-10-17
|
||||||
description `USBLMCV4`, USB VID/PID `9588:9899`, vendor-specific class, and
|
description `USBLMCV4`, USB VID/PID `9588:9899`, vendor-specific class, and
|
||||||
USB revision descriptor `0005`. No compatible function driver is installed
|
USB revision descriptor `0005`. No compatible function driver is installed
|
||||||
on the development computer; no endpoint was opened.
|
on the development computer; no endpoint was opened.
|
||||||
|
- Four LightBurn exports are preserved privately with SHA-256 manifests and
|
||||||
|
Git LFS. Their public evidence records contain no private source locators.
|
||||||
|
- All three bundle manifests identify LightBurn `2.1.03`.
|
||||||
|
- The JPT export confirms a `JCZFiber`/`LibUSB` device profile, 110 x 110 mm
|
||||||
|
work area, enabled Q-pulse-width control, `QPulseWidth` cut-list fields and
|
||||||
|
a require-frame-before-start setting.
|
||||||
|
- The Eduard export confirms a Ruida/Serial profile with a 1500 x 1000 mm work
|
||||||
|
area. A separate 500 x 300 mm Ruida profile remains physically unassigned.
|
||||||
- No vendor executable, plugin, DLL, or driver was run. No USB capture, framing,
|
- No vendor executable, plugin, DLL, or driver was run. No USB capture, framing,
|
||||||
machine command, or laser output was performed.
|
machine command, or laser output was performed.
|
||||||
|
|
||||||
## Pending external acquisition
|
## Pending external acquisition
|
||||||
|
|
||||||
The current development computer is not the LightBurn control computer: no
|
These items remain pending from the actual control machine:
|
||||||
LightBurn executable or local LightBurn preferences directory was present.
|
|
||||||
Consequently, these items remain pending from the actual control machine:
|
|
||||||
|
|
||||||
- Help → About screenshot;
|
|
||||||
- full `.lbzip` bundle and `.lbprefs` export;
|
|
||||||
- closed-application preferences-folder archive;
|
- closed-application preferences-folder archive;
|
||||||
- Device Settings screenshots;
|
- Device Settings screenshots;
|
||||||
- known-working `.lbrn2` examples;
|
- known-working `.lbrn2` examples;
|
||||||
- safe exterior hardware/label photographs and startup/interlock notes;
|
- safe exterior hardware/label photographs and startup/interlock notes;
|
||||||
- stock-driver identity and version from the actual LightBurn control computer.
|
- stock-driver identity and version from the actual LightBurn control computer.
|
||||||
|
|
||||||
|
An About screenshot is useful corroboration, but the imported bundle manifests
|
||||||
|
already establish version `2.1.03`.
|
||||||
|
|
||||||
Collect them directly into a dated directory under PrivateStash by following
|
Collect them directly into a dated directory under PrivateStash by following
|
||||||
the [LightBurn checklist](../collection/lightburn.md). Do not use Google Drive
|
the [LightBurn checklist](../collection/lightburn.md). Do not use Google Drive
|
||||||
as an intermediate project workspace and do not generate Support Data.
|
as an intermediate project workspace and do not generate Support Data.
|
||||||
|
|
||||||
Phase 0 remains open until these control-machine artifacts are hashed,
|
Phase 0 remains open until the safety- and interoperability-relevant remainder
|
||||||
committed, pushed, and represented by sanitized public evidence.
|
is hashed, committed, pushed, and represented by sanitized public evidence.
|
||||||
|
|
||||||
The work that does not depend on this acquisition can proceed in parallel.
|
The work that does not depend on this acquisition can proceed in parallel.
|
||||||
The [product and research roadmap](../roadmap.md) defines the offline application
|
The [product and research roadmap](../roadmap.md) defines the offline application
|
||||||
|
|
|
||||||
4
evidence/public-lightburn-exports.jsonl
Normal file
4
evidence/public-lightburn-exports.jsonl
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
{"analysis_refs":["docs/research/lightburn-device-exports-2026-10-19.md"],"artifact_id":"sha256-e16fdb0aa7c374c4c94d","classification":"private-sensitive","media_type":"application/zip","observed_at_utc":"2026-10-19T08:06:14Z","origin":"user-provided-local-lightburn-export","sha256":"e16fdb0aa7c374c4c94de9b4ecf4f0be1e1167f91c8f51517b060dde900880de","size_bytes":20309}
|
||||||
|
{"analysis_refs":["docs/research/lightburn-device-exports-2026-10-19.md"],"artifact_id":"sha256-fc6cf52f4ef815dd5037","classification":"private-sensitive","media_type":"application/zip","observed_at_utc":"2026-10-19T08:06:14Z","origin":"user-provided-local-lightburn-export","sha256":"fc6cf52f4ef815dd5037e11a893cefce4009b4965c11776d931e501ccf10a713","size_bytes":5720}
|
||||||
|
{"analysis_refs":["docs/research/lightburn-device-exports-2026-10-19.md"],"artifact_id":"sha256-88c762adcb8e9693c913","classification":"private-sensitive","media_type":"application/octet-stream","observed_at_utc":"2026-10-19T08:06:14Z","origin":"user-provided-local-lightburn-export","sha256":"88c762adcb8e9693c9132473a9d90c69eaf768b96f12e8af71e89adfb10b4cfa","size_bytes":97356}
|
||||||
|
{"analysis_refs":["docs/research/lightburn-device-exports-2026-10-19.md"],"artifact_id":"sha256-d422e9886e29ed666c07","classification":"private-sensitive","media_type":"application/zip","observed_at_utc":"2026-10-19T08:06:14Z","origin":"user-provided-local-lightburn-export","sha256":"d422e9886e29ed666c077a0e7bab9a6c3d53fc938365b7b773d79c529b55c0f0","size_bytes":8798}
|
||||||
|
|
@ -8,6 +8,17 @@ ROOT = Path(__file__).resolve().parents[1]
|
||||||
|
|
||||||
|
|
||||||
class PublicEvidenceTests(unittest.TestCase):
|
class PublicEvidenceTests(unittest.TestCase):
|
||||||
|
def _manifest_paths(self) -> list[Path]:
|
||||||
|
return sorted((ROOT / "evidence").glob("public-*.jsonl"))
|
||||||
|
|
||||||
|
def _entries(self) -> list[dict]:
|
||||||
|
return [
|
||||||
|
json.loads(line)
|
||||||
|
for path in self._manifest_paths()
|
||||||
|
for line in path.read_text(encoding="utf-8").splitlines()
|
||||||
|
if line
|
||||||
|
]
|
||||||
|
|
||||||
def test_public_evidence_matches_manifest_contract(self) -> None:
|
def test_public_evidence_matches_manifest_contract(self) -> None:
|
||||||
schema = json.loads(
|
schema = json.loads(
|
||||||
(ROOT / "schemas" / "artifact-manifest.schema.json").read_text(encoding="utf-8")
|
(ROOT / "schemas" / "artifact-manifest.schema.json").read_text(encoding="utf-8")
|
||||||
|
|
@ -18,13 +29,10 @@ class PublicEvidenceTests(unittest.TestCase):
|
||||||
digest_pattern = re.compile(schema["properties"]["sha256"]["pattern"])
|
digest_pattern = re.compile(schema["properties"]["sha256"]["pattern"])
|
||||||
classifications = set(schema["properties"]["classification"]["enum"])
|
classifications = set(schema["properties"]["classification"]["enum"])
|
||||||
|
|
||||||
lines = (ROOT / "evidence" / "public-installer-configs.jsonl").read_text(
|
paths = self._manifest_paths()
|
||||||
encoding="utf-8"
|
self.assertGreaterEqual(len(paths), 2)
|
||||||
).splitlines()
|
|
||||||
self.assertEqual(len(lines), 9)
|
|
||||||
|
|
||||||
for line in lines:
|
for entry in self._entries():
|
||||||
entry = json.loads(line)
|
|
||||||
self.assertFalse(required - set(entry))
|
self.assertFalse(required - set(entry))
|
||||||
self.assertFalse(set(entry) - allowed)
|
self.assertFalse(set(entry) - allowed)
|
||||||
self.assertRegex(entry["artifact_id"], artifact_pattern)
|
self.assertRegex(entry["artifact_id"], artifact_pattern)
|
||||||
|
|
@ -35,15 +43,21 @@ class PublicEvidenceTests(unittest.TestCase):
|
||||||
self.assertNotIn("source_locator", entry)
|
self.assertNotIn("source_locator", entry)
|
||||||
|
|
||||||
def test_public_evidence_has_unique_content_ids(self) -> None:
|
def test_public_evidence_has_unique_content_ids(self) -> None:
|
||||||
entries = [
|
entries = self._entries()
|
||||||
json.loads(line)
|
|
||||||
for line in (ROOT / "evidence" / "public-installer-configs.jsonl")
|
|
||||||
.read_text(encoding="utf-8")
|
|
||||||
.splitlines()
|
|
||||||
]
|
|
||||||
ids = [entry["artifact_id"] for entry in entries]
|
ids = [entry["artifact_id"] for entry in entries]
|
||||||
self.assertEqual(len(ids), len(set(ids)))
|
self.assertEqual(len(ids), len(set(ids)))
|
||||||
|
|
||||||
|
def test_expected_manifest_entry_counts(self) -> None:
|
||||||
|
expected = {
|
||||||
|
"public-installer-configs.jsonl": 9,
|
||||||
|
"public-lightburn-exports.jsonl": 4,
|
||||||
|
}
|
||||||
|
actual = {
|
||||||
|
path.name: len(path.read_text(encoding="utf-8").splitlines())
|
||||||
|
for path in self._manifest_paths()
|
||||||
|
}
|
||||||
|
self.assertEqual(actual, expected)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue