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;
|
||||
- the physical controller has been passively identified by Windows as
|
||||
`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;
|
||||
- no USB endpoint has been opened and no controller command, galvo movement,
|
||||
framing, marking, or laser output has occurred;
|
||||
- the public tests, provenance checks, leak guard, and clean-clone validation
|
||||
pass.
|
||||
|
||||
Phase 0 remains open while we collect the LightBurn bundle, preferences,
|
||||
known-working projects, device screenshots, machine photos, and operator notes
|
||||
directly from the actual control computer.
|
||||
Phase 0 remains open while we collect known-working LightBurn projects, device
|
||||
screenshots, the closed-application preferences folder, machine photos, and
|
||||
operator notes directly from the actual control computer. The bundle and
|
||||
exported preferences are already preserved and analyzed.
|
||||
|
||||
## The important discovery
|
||||
|
||||
|
|
@ -55,16 +61,17 @@ BalorMK. This remains a proposed decision until the offline proofs in
|
|||
|
||||
## 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;
|
||||
2. prove that an external Rayforge addon can register a binary no-device
|
||||
driver on Windows;
|
||||
3. translate a small Rayforge operation stream into a deterministic JCZ trace
|
||||
and compare it with BalorMK;
|
||||
4. test Rayforge's existing LightBurn import against galvo/MOPA fixtures;
|
||||
5. accept, revise, or reject the proposed reuse architecture from evidence;
|
||||
6. write and review a separate hardware protocol before any live controller
|
||||
1. collect known-working `.lbrn2` projects and the remaining screenshots,
|
||||
photos, preferences folder and operator notes;
|
||||
2. extend the synthetic import tests with the now-observed `QPulseWidth`
|
||||
evidence, without assuming its `.lbrn2` representation;
|
||||
3. define the minimum Rayforge JCZ device-profile/import extension and finish
|
||||
controller-list buffering and safe state ordering offline;
|
||||
4. accept, revise, or reject the proposed reuse architecture from evidence;
|
||||
5. write and review a separate hardware protocol before any live controller
|
||||
communication.
|
||||
|
||||
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)
|
||||
- [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)
|
||||
- [LightBurn device-export analysis](docs/research/lightburn-device-exports-2026-10-19.md)
|
||||
- [Sanitized machine profile](docs/research/machine-profile.yaml)
|
||||
- [110/300 configuration comparison](docs/research/config-comparison.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
|
||||
height: 300
|
||||
lightburn:
|
||||
version: null
|
||||
version: 2.1.03
|
||||
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:
|
||||
vid: "9588"
|
||||
pid: "9899"
|
||||
|
|
@ -45,8 +50,16 @@ evidence:
|
|||
- artifact_id: sha256-ebfe631958b9522533ff
|
||||
sha256: ebfe631958b9522533ffb1e78c8961073e3549039053ea0d56e4c82cfe8bff83
|
||||
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:
|
||||
- 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.
|
||||
- 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.
|
||||
- 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.
|
||||
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
|
||||
pulse-width field. Consequently, the imported job is explicitly classified as
|
||||
unsafe for JCZ encoding rather than being completed with a guessed value.
|
||||
LightBurn project fixtures and importer contain no evidence-backed mapping for
|
||||
a MOPA pulse-width field. A later private LightBurn device-library export
|
||||
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
|
||||
`9ebce7b5b3388abfeed024e25f8f46001260bf814da19808bfc83fb6554fc26e`.
|
||||
|
|
@ -28,8 +31,12 @@ The golden result is `tests/fixtures/rayforge-lightburn-mopa-import.json`.
|
|||
`overrideFrequency` elements.
|
||||
- **Observed:** generic parsing retains these elements in source metadata.
|
||||
- **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
|
||||
known-working galvo project.
|
||||
- **Observed after this spike:** a LightBurn `2.1.03` device-library export
|
||||
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
|
||||
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
|
||||
and common process settings, but it does not yet satisfy M1's MOPA parameter
|
||||
survival requirement. The narrowest likely extension is an importer mapping
|
||||
for frequency plus a separately evidenced pulse-width field, followed by an
|
||||
explicit validation gate. A private known-working LightBurn project is still
|
||||
needed to establish the pulse-width representation before implementing that
|
||||
mapping.
|
||||
for frequency plus `QPulseWidth`, followed by an explicit unit conversion and
|
||||
validation gate. A private known-working LightBurn project is still needed to
|
||||
establish project serialization before implementing that mapping.
|
||||
|
||||
No USB enumeration, controller command, motion or emission was attempted.
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# Product and research roadmap
|
||||
|
||||
Last updated: 2026-10-18
|
||||
Last updated: 2026-10-19
|
||||
|
||||
## Destination
|
||||
|
||||
|
|
@ -46,7 +46,8 @@ evidence.
|
|||
The collected installer snapshot establishes:
|
||||
|
||||
- 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;
|
||||
- exact hashes for the opaque, lens-specific `markcfg7` profiles;
|
||||
- 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;
|
||||
- status, interlock, error, abort, and recovery behavior;
|
||||
- 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
|
||||
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)
|
||||
confirms that Rayforge preserves geometry, power, speed and passes and retains
|
||||
an observed LightBurn frequency value in raw source metadata. Frequency is not
|
||||
mapped into workflow settings, and no evidence-backed pulse-width field was
|
||||
found, so the job deliberately fails the JCZ encoding gate. A private
|
||||
known-working galvo fixture is required before implementing the missing MOPA
|
||||
mapping.
|
||||
mapped into workflow settings. A later real device export identifies
|
||||
`QPulseWidth` and its nanosecond UI contract, but project serialization remains
|
||||
unknown, so the job still deliberately fails the JCZ encoding gate. A private
|
||||
known-working `.lbrn2` fixture is required before implementing the missing
|
||||
MOPA mapping.
|
||||
|
||||
The architecture decision remains proposed until these spikes produce
|
||||
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:
|
||||
|
||||
1. collect the pending LightBurn data from the control PC as one local archive;
|
||||
2. run the stock MeerK40t mock-controller evaluation;
|
||||
3. prove the Rayforge external-addon and binary-driver registration seam;
|
||||
4. build one no-I/O Rayforge-to-JCZ encoder spike and golden trace comparison;
|
||||
5. test Rayforge's existing LightBurn import against galvo/MOPA fixtures;
|
||||
6. accept, amend or reject ADR 0002 from the results;
|
||||
7. separately produce a written M3 hardware-research protocol before any USB
|
||||
access or controller command.
|
||||
1. collect two or three known-working `.lbrn2` projects plus the remaining
|
||||
device screenshots, preferences folder, photos and operator notes;
|
||||
2. add a sanitized synthetic JCZ `.lbdev` fixture and characterize the exact
|
||||
gaps in Rayforge's device importer;
|
||||
3. implement and test the smallest evidence-backed JCZ profile-import seam,
|
||||
keeping project `QPulseWidth` mapping gated until a real project confirms
|
||||
its serialization;
|
||||
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
|
||||
until item 7 is reviewed and the physical setup is ready.
|
||||
Hardware work cannot proceed until item 6 is reviewed and the physical setup
|
||||
is ready.
|
||||
|
||||
## Decision rules
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# Phase 0 status
|
||||
|
||||
Last updated: 2026-10-17
|
||||
Last updated: 2026-10-19
|
||||
|
||||
## Completed
|
||||
|
||||
|
|
@ -22,29 +22,36 @@ Last updated: 2026-10-17
|
|||
description `USBLMCV4`, USB VID/PID `9588:9899`, vendor-specific class, and
|
||||
USB revision descriptor `0005`. No compatible function driver is installed
|
||||
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,
|
||||
machine command, or laser output was performed.
|
||||
|
||||
## Pending external acquisition
|
||||
|
||||
The current development computer is not the LightBurn control computer: no
|
||||
LightBurn executable or local LightBurn preferences directory was present.
|
||||
Consequently, these items remain pending from the actual control machine:
|
||||
These items remain pending from the actual control machine:
|
||||
|
||||
- Help → About screenshot;
|
||||
- full `.lbzip` bundle and `.lbprefs` export;
|
||||
- closed-application preferences-folder archive;
|
||||
- Device Settings screenshots;
|
||||
- known-working `.lbrn2` examples;
|
||||
- safe exterior hardware/label photographs and startup/interlock notes;
|
||||
- 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
|
||||
the [LightBurn checklist](../collection/lightburn.md). Do not use Google Drive
|
||||
as an intermediate project workspace and do not generate Support Data.
|
||||
|
||||
Phase 0 remains open until these control-machine artifacts are hashed,
|
||||
committed, pushed, and represented by sanitized public evidence.
|
||||
Phase 0 remains open until the safety- and interoperability-relevant remainder
|
||||
is hashed, committed, pushed, and represented by sanitized public evidence.
|
||||
|
||||
The work that does not depend on this acquisition can proceed in parallel.
|
||||
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):
|
||||
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:
|
||||
schema = json.loads(
|
||||
(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"])
|
||||
classifications = set(schema["properties"]["classification"]["enum"])
|
||||
|
||||
lines = (ROOT / "evidence" / "public-installer-configs.jsonl").read_text(
|
||||
encoding="utf-8"
|
||||
).splitlines()
|
||||
self.assertEqual(len(lines), 9)
|
||||
paths = self._manifest_paths()
|
||||
self.assertGreaterEqual(len(paths), 2)
|
||||
|
||||
for line in lines:
|
||||
entry = json.loads(line)
|
||||
for entry in self._entries():
|
||||
self.assertFalse(required - set(entry))
|
||||
self.assertFalse(set(entry) - allowed)
|
||||
self.assertRegex(entry["artifact_id"], artifact_pattern)
|
||||
|
|
@ -35,15 +43,21 @@ class PublicEvidenceTests(unittest.TestCase):
|
|||
self.assertNotIn("source_locator", entry)
|
||||
|
||||
def test_public_evidence_has_unique_content_ids(self) -> None:
|
||||
entries = [
|
||||
json.loads(line)
|
||||
for line in (ROOT / "evidence" / "public-installer-configs.jsonl")
|
||||
.read_text(encoding="utf-8")
|
||||
.splitlines()
|
||||
]
|
||||
entries = self._entries()
|
||||
ids = [entry["artifact_id"] for entry in entries]
|
||||
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__":
|
||||
unittest.main()
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue