docs: scaffold polisher-control foundation
This commit is contained in:
130
shared/machine/fullum-alpha.capabilities.v1.json
Normal file
130
shared/machine/fullum-alpha.capabilities.v1.json
Normal file
@@ -0,0 +1,130 @@
|
||||
{
|
||||
"schema_version": "machine-capabilities.v1",
|
||||
"machine_id": "fullum-alpha",
|
||||
"machine_family": "swing-arm",
|
||||
"machine_name": "Fullum swing-arm polisher",
|
||||
"controller_version": "polisher-control/0.1.0",
|
||||
"supported_motion_families": [
|
||||
"swing-arm-rosette"
|
||||
],
|
||||
"force_range_n": [
|
||||
0,
|
||||
80
|
||||
],
|
||||
"table_rpm_range": [
|
||||
0,
|
||||
5.0
|
||||
],
|
||||
"spindle_rpm_range": [
|
||||
0,
|
||||
80
|
||||
],
|
||||
"cam_amplitude_range_deg": [
|
||||
0,
|
||||
45
|
||||
],
|
||||
"cam_offset_range_deg": [
|
||||
-30,
|
||||
30
|
||||
],
|
||||
"force_modulation": {
|
||||
"supported": true,
|
||||
"max_harmonics": 3,
|
||||
"max_amplitude_n": 20.0,
|
||||
"notes": "Angle-synchronized force modulation from live table encoder angle; validate during commissioning."
|
||||
},
|
||||
"supported_dither_profiles": [
|
||||
"none",
|
||||
"default"
|
||||
],
|
||||
"segment_duration_limits": {
|
||||
"min_s": 10,
|
||||
"max_s": 7200
|
||||
},
|
||||
"pause_resume_support": true,
|
||||
"telemetry_channels": [
|
||||
{
|
||||
"name": "timestamp_us",
|
||||
"unit": "see docs/05-telemetry-channel-spec-v1.md",
|
||||
"sample_rate_hz": 100
|
||||
},
|
||||
{
|
||||
"name": "table_angle_deg",
|
||||
"unit": "see docs/05-telemetry-channel-spec-v1.md",
|
||||
"sample_rate_hz": 100
|
||||
},
|
||||
{
|
||||
"name": "arm_angle_deg",
|
||||
"unit": "see docs/05-telemetry-channel-spec-v1.md",
|
||||
"sample_rate_hz": 100
|
||||
},
|
||||
{
|
||||
"name": "fz_n",
|
||||
"unit": "see docs/05-telemetry-channel-spec-v1.md",
|
||||
"sample_rate_hz": 100
|
||||
},
|
||||
{
|
||||
"name": "mx",
|
||||
"unit": "see docs/05-telemetry-channel-spec-v1.md",
|
||||
"sample_rate_hz": 100
|
||||
},
|
||||
{
|
||||
"name": "my",
|
||||
"unit": "see docs/05-telemetry-channel-spec-v1.md",
|
||||
"sample_rate_hz": 100
|
||||
},
|
||||
{
|
||||
"name": "mz",
|
||||
"unit": "see docs/05-telemetry-channel-spec-v1.md",
|
||||
"sample_rate_hz": 100
|
||||
},
|
||||
{
|
||||
"name": "spindle_rpm_actual",
|
||||
"unit": "see docs/05-telemetry-channel-spec-v1.md",
|
||||
"sample_rate_hz": 100
|
||||
},
|
||||
{
|
||||
"name": "table_rpm_actual",
|
||||
"unit": "see docs/05-telemetry-channel-spec-v1.md",
|
||||
"sample_rate_hz": 100
|
||||
},
|
||||
{
|
||||
"name": "arm_amplitude_deg_derived",
|
||||
"unit": "see docs/05-telemetry-channel-spec-v1.md",
|
||||
"sample_rate_hz": 100
|
||||
},
|
||||
{
|
||||
"name": "arm_center_deg_derived",
|
||||
"unit": "see docs/05-telemetry-channel-spec-v1.md",
|
||||
"sample_rate_hz": 100
|
||||
},
|
||||
{
|
||||
"name": "machine_state",
|
||||
"unit": "see docs/05-telemetry-channel-spec-v1.md",
|
||||
"sample_rate_hz": 100
|
||||
},
|
||||
{
|
||||
"name": "force_setpoint_n",
|
||||
"unit": "see docs/05-telemetry-channel-spec-v1.md",
|
||||
"sample_rate_hz": 100
|
||||
}
|
||||
],
|
||||
"safety_limits": {
|
||||
"max_force_n": 80,
|
||||
"max_table_rpm": 5.0,
|
||||
"max_spindle_rpm": 80,
|
||||
"notes": "Initial source-aligned limits; final hardware commissioning must verify."
|
||||
},
|
||||
"known_constraints": [
|
||||
"Manual mode is the first production target.",
|
||||
"No powered Zero-G/admittance mode in v1.",
|
||||
"Oscillation amplitude/center are operator-entered configuration in v1, not actuated cam commands.",
|
||||
"Controller rejects unknown controller-job fields rather than silently ignoring them."
|
||||
],
|
||||
"unknowns": [
|
||||
"Exact KWR75B-CAN frame map, scaling, status bits, and update rate.",
|
||||
"Final ODrive runtime interface and command scaling.",
|
||||
"Final SV2A-2150 torque/current command scaling and Iq monitor mapping.",
|
||||
"Final safety relay model and wiring details."
|
||||
]
|
||||
}
|
||||
0
shared/protocol/.gitkeep
Normal file
0
shared/protocol/.gitkeep
Normal file
11
shared/schemas/README.md
Normal file
11
shared/schemas/README.md
Normal file
@@ -0,0 +1,11 @@
|
||||
# Shared Schemas
|
||||
|
||||
Mirrored from the current Polisher Software Suite schema bundle for implementation alignment.
|
||||
|
||||
Important:
|
||||
- `controller-job.v1` is what this controller accepts from `polisher-post`.
|
||||
- `job.v1` is upstream planning input and must be rejected by `polisher-control`.
|
||||
- `run-log.v1` is emitted by `polisher-control` after program execution.
|
||||
- `manual-session-log.v1` is currently documented in repo docs/spec; formal schema can be added when Antoine locks it.
|
||||
|
||||
Do not rename fields locally without coordinating with Antoine because downstream tools depend on stable names.
|
||||
117
shared/schemas/controller-job.schema.json
Normal file
117
shared/schemas/controller-job.schema.json
Normal file
@@ -0,0 +1,117 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://polisher-suite.local/schemas/controller-job.schema.json",
|
||||
"title": "Controller Job Package",
|
||||
"description": "Translated execution package produced by polisher-post for polisher-control. Represents translated truth.",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"schema_version",
|
||||
"controller_job_id",
|
||||
"job_id",
|
||||
"machine_id",
|
||||
"machine_capabilities_ref",
|
||||
"controller_version",
|
||||
"translated_at",
|
||||
"translated_by",
|
||||
"segments",
|
||||
"translation_losses"
|
||||
],
|
||||
"properties": {
|
||||
"schema_version": {
|
||||
"type": "string",
|
||||
"const": "controller-job.v1"
|
||||
},
|
||||
"controller_job_id": {
|
||||
"type": "string",
|
||||
"description": "Stable unique identifier for this translated package."
|
||||
},
|
||||
"job_id": {
|
||||
"type": "string",
|
||||
"description": "Back-reference to the source planning job."
|
||||
},
|
||||
"machine_id": {
|
||||
"type": "string",
|
||||
"description": "Target machine identifier."
|
||||
},
|
||||
"machine_capabilities_ref": {
|
||||
"type": "string",
|
||||
"description": "Reference to the machine-capabilities document used for translation."
|
||||
},
|
||||
"controller_version": {
|
||||
"type": "string",
|
||||
"description": "Target controller software version."
|
||||
},
|
||||
"translated_at": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
},
|
||||
"translated_by": {
|
||||
"type": "string",
|
||||
"description": "polisher-post version that performed the translation."
|
||||
},
|
||||
"translation_notes": {
|
||||
"type": "string",
|
||||
"description": "Summary of constraints applied during translation."
|
||||
},
|
||||
"segments": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"$ref": "#/$defs/segment"
|
||||
}
|
||||
},
|
||||
"translation_losses": {
|
||||
"type": "array",
|
||||
"description": "Explicit record of every constraint, clip, or approximation applied.",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": ["source_pass_id", "field", "description"],
|
||||
"properties": {
|
||||
"source_pass_id": { "type": "string" },
|
||||
"field": { "type": "string" },
|
||||
"planned_value": {},
|
||||
"translated_value": {},
|
||||
"description": { "type": "string" }
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"$defs": {
|
||||
"segment": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"segment_id",
|
||||
"sequence_index",
|
||||
"source_pass_id",
|
||||
"duration_s",
|
||||
"commanded_force_n",
|
||||
"commanded_table_rpm",
|
||||
"commanded_spindle_rpm"
|
||||
],
|
||||
"properties": {
|
||||
"segment_id": { "type": "string" },
|
||||
"sequence_index": { "type": "integer", "minimum": 1 },
|
||||
"source_pass_id": {
|
||||
"type": "string",
|
||||
"description": "Back-reference to the planning pass this segment came from."
|
||||
},
|
||||
"duration_s": { "type": "number", "minimum": 0 },
|
||||
"commanded_force_n": { "type": "number", "minimum": 0 },
|
||||
"commanded_table_rpm": { "type": "number", "minimum": 0 },
|
||||
"commanded_spindle_rpm": { "type": "number", "minimum": 0 },
|
||||
"commanded_cam_amplitude_deg": { "type": "number" },
|
||||
"commanded_cam_offset_deg": { "type": "number" },
|
||||
"force_modulation": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"harmonic": { "type": "integer" },
|
||||
"amplitude_n": { "type": "number" },
|
||||
"phase_deg": { "type": "number" }
|
||||
}
|
||||
},
|
||||
"dither_profile": { "type": "string" },
|
||||
"notes": { "type": "string" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
32
shared/schemas/examples/controller-job.example.json
Normal file
32
shared/schemas/examples/controller-job.example.json
Normal file
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"schema_version": "controller-job.v1",
|
||||
"controller_job_id": "cjob-2026-07-001",
|
||||
"job_id": "job-2026-07-001",
|
||||
"machine_id": "fullum-alpha",
|
||||
"machine_capabilities_ref": "machine-capabilities-fullum-alpha-v1",
|
||||
"controller_version": "polisher-control/0.1.0",
|
||||
"translated_at": "2026-07-15T10:15:00Z",
|
||||
"translated_by": "polisher-post/0.1.0",
|
||||
"translation_notes": "All setpoints within machine limits. No clipping required.",
|
||||
"segments": [
|
||||
{
|
||||
"segment_id": "seg-01",
|
||||
"sequence_index": 1,
|
||||
"source_pass_id": "pass-01",
|
||||
"duration_s": 1200,
|
||||
"commanded_force_n": 45.0,
|
||||
"commanded_table_rpm": 4.0,
|
||||
"commanded_spindle_rpm": 40.0,
|
||||
"commanded_cam_amplitude_deg": 31.3,
|
||||
"commanded_cam_offset_deg": 0.0,
|
||||
"force_modulation": {
|
||||
"harmonic": 2,
|
||||
"amplitude_n": 5.0,
|
||||
"phase_deg": 37.2
|
||||
},
|
||||
"dither_profile": "none",
|
||||
"notes": "Direct translation — no segmentation needed for 1200s duration."
|
||||
}
|
||||
],
|
||||
"translation_losses": []
|
||||
}
|
||||
71
shared/schemas/examples/job.example.json
Normal file
71
shared/schemas/examples/job.example.json
Normal file
@@ -0,0 +1,71 @@
|
||||
{
|
||||
"schema_version": "job.v1",
|
||||
"job_id": "job-2026-07-001",
|
||||
"mirror_id": "gigabit-m1",
|
||||
"machine_family": "swing-arm",
|
||||
"source_map_id": "ifg-2026-07-14-pre",
|
||||
"target_id": "target-m1-final-figure",
|
||||
"created_at": "2026-07-15T09:30:00Z",
|
||||
"created_by": "antoine",
|
||||
"planner_version": "polisher-sim/0.6.0",
|
||||
"calibration_state_ref": "cal-2026-06-fullum-alpha",
|
||||
"strategy_summary": {
|
||||
"intent": "Reduce dominant astigmatism using m=2 force modulation on 280mm tool",
|
||||
"confidence": 0.72,
|
||||
"notes": "Single-pass conservative correction. Dither disabled for baseline comparison."
|
||||
},
|
||||
"passes": [
|
||||
{
|
||||
"pass_id": "pass-01",
|
||||
"sequence_index": 1,
|
||||
"objective": "Astigmatism reduction via force modulation",
|
||||
"preset_name": "figuring_standard",
|
||||
"duration_s": 1200,
|
||||
"force_n": 45.0,
|
||||
"table_rpm": 4.0,
|
||||
"spindle_rpm": 40.0,
|
||||
"motion_family": "swing-arm-rosette",
|
||||
"motion_params": {
|
||||
"cam_amplitude_deg": 31.3,
|
||||
"cam_offset_deg": 0.0,
|
||||
"osc_hz": 0.25
|
||||
},
|
||||
"dither_profile": "none",
|
||||
"force_modulation": {
|
||||
"harmonic": 2,
|
||||
"amplitude_n": 5.0,
|
||||
"phase_deg": 37.2
|
||||
},
|
||||
"notes": "Phase derived from Zernike fit of pre-polish interferogram."
|
||||
}
|
||||
],
|
||||
"predicted_outcome": {
|
||||
"removal_rms_nm": 18.5,
|
||||
"removal_pv_nm": 62.0,
|
||||
"residual_zernikes": {
|
||||
"Z4": -2.1,
|
||||
"Z5": 12.3,
|
||||
"Z6": -8.7,
|
||||
"Z7": 15.1,
|
||||
"Z8": -3.2,
|
||||
"Z9": 4.5,
|
||||
"Z10": -2.8
|
||||
}
|
||||
},
|
||||
"uncertainty": {
|
||||
"removal_rms_nm_range": [14.0, 24.0],
|
||||
"notes": "Uncertainty dominated by Preston coefficient calibration spread."
|
||||
},
|
||||
"attachments": [
|
||||
{
|
||||
"filename": "predicted_removal.csv",
|
||||
"role": "predicted_removal_map",
|
||||
"description": "2D removal map in nm, 256x256 grid"
|
||||
},
|
||||
{
|
||||
"filename": "pre_surface.csv",
|
||||
"role": "input_surface_map",
|
||||
"description": "Pre-polish surface map used as planning input"
|
||||
}
|
||||
]
|
||||
}
|
||||
51
shared/schemas/examples/machine-capabilities.example.json
Normal file
51
shared/schemas/examples/machine-capabilities.example.json
Normal file
@@ -0,0 +1,51 @@
|
||||
{
|
||||
"schema_version": "machine-capabilities.v1",
|
||||
"machine_id": "fullum-alpha",
|
||||
"machine_family": "swing-arm",
|
||||
"machine_name": "Fullum Swing-Arm Polisher",
|
||||
"controller_version": "polisher-control/0.1.0",
|
||||
"last_verified": "2026-06-01T00:00:00Z",
|
||||
"supported_motion_families": ["swing-arm-rosette"],
|
||||
"force_range_n": [5, 200],
|
||||
"table_rpm_range": [0.5, 10.0],
|
||||
"spindle_rpm_range": [10, 120],
|
||||
"cam_amplitude_range_deg": [1.0, 31.3],
|
||||
"cam_offset_range_deg": [-30.0, 30.0],
|
||||
"force_modulation": {
|
||||
"supported": true,
|
||||
"max_harmonics": 3,
|
||||
"max_amplitude_n": 24.0,
|
||||
"notes": "m=2 astigmatism and m=3 trefoil are proven channels. m=1 coma is unreliable (score 0.09)."
|
||||
},
|
||||
"supported_dither_profiles": ["none", "default"],
|
||||
"segment_duration_limits": {
|
||||
"min_s": 30,
|
||||
"max_s": 7200
|
||||
},
|
||||
"pause_resume_support": true,
|
||||
"telemetry_channels": [
|
||||
{ "name": "table_rpm", "unit": "RPM", "sample_rate_hz": 100 },
|
||||
{ "name": "spindle_rpm", "unit": "RPM", "sample_rate_hz": 100 },
|
||||
{ "name": "force_n", "unit": "N", "sample_rate_hz": 100 },
|
||||
{ "name": "arm_angle_deg", "unit": "degrees", "sample_rate_hz": 100 },
|
||||
{ "name": "table_angle_deg", "unit": "degrees", "sample_rate_hz": 100 },
|
||||
{ "name": "timestamp_ms", "unit": "ms", "sample_rate_hz": 100 }
|
||||
],
|
||||
"safety_limits": {
|
||||
"max_force_n": 200,
|
||||
"max_table_rpm": 10.0,
|
||||
"max_spindle_rpm": 120,
|
||||
"notes": "Force hard-limited by load cell interlock. RPM limits are VFD/servo configured."
|
||||
},
|
||||
"known_constraints": [
|
||||
"Cam amplitude is not servo-programmable — must be set mechanically before run.",
|
||||
"Force modulation bandwidth limited to ~5 Hz by actuator response.",
|
||||
"Table encoder is absolute but may have 1-2 count jitter.",
|
||||
"Serial interface to Teensy limits command update rate to ~50 Hz effective."
|
||||
],
|
||||
"unknowns": [
|
||||
"Exact force modulation phase accuracy at m=3 harmonic — not yet validated on hardware.",
|
||||
"Thermal drift effect on force sensor over runs longer than 1 hour.",
|
||||
"Arm pivot play magnitude under varying force loads."
|
||||
]
|
||||
}
|
||||
43
shared/schemas/examples/manifest.example.json
Normal file
43
shared/schemas/examples/manifest.example.json
Normal file
@@ -0,0 +1,43 @@
|
||||
{
|
||||
"schema_version": "manifest.v1",
|
||||
"manifest_id": "manifest-job-2026-07-001",
|
||||
"bundle_type": "job",
|
||||
"source_id": "job-2026-07-001",
|
||||
"created_at": "2026-07-15T09:31:00Z",
|
||||
"created_by": "polisher-sim/0.6.0",
|
||||
"entries": [
|
||||
{
|
||||
"filename": "job.json",
|
||||
"role": "primary",
|
||||
"hash_sha256": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2",
|
||||
"size_bytes": 2007,
|
||||
"content_type": "application/json",
|
||||
"description": "Frozen planning job package."
|
||||
},
|
||||
{
|
||||
"filename": "predicted_removal.csv",
|
||||
"role": "attachment",
|
||||
"hash_sha256": "b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3",
|
||||
"size_bytes": 524288,
|
||||
"content_type": "text/csv",
|
||||
"description": "Predicted removal map, 256x256 grid, nm."
|
||||
},
|
||||
{
|
||||
"filename": "pre_surface.csv",
|
||||
"role": "attachment",
|
||||
"hash_sha256": "c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4",
|
||||
"size_bytes": 524288,
|
||||
"content_type": "text/csv",
|
||||
"description": "Pre-polish surface map used as planning input."
|
||||
},
|
||||
{
|
||||
"filename": "manifest.json",
|
||||
"role": "manifest",
|
||||
"hash_sha256": "0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"size_bytes": 0,
|
||||
"content_type": "application/json",
|
||||
"description": "This manifest (self-reference, hash zeroed by convention)."
|
||||
}
|
||||
],
|
||||
"notes": "July proving scenario — single-pass astigmatism correction job bundle."
|
||||
}
|
||||
64
shared/schemas/examples/run-log.example.json
Normal file
64
shared/schemas/examples/run-log.example.json
Normal file
@@ -0,0 +1,64 @@
|
||||
{
|
||||
"schema_version": "run-log.v1",
|
||||
"run_id": "run-2026-07-001",
|
||||
"job_id": "job-2026-07-001",
|
||||
"controller_job_id": "cjob-2026-07-001",
|
||||
"controller_version": "polisher-control/0.1.0",
|
||||
"machine_id": "fullum-alpha",
|
||||
"started_at": "2026-07-17T14:00:00Z",
|
||||
"ended_at": "2026-07-17T14:20:35Z",
|
||||
"result_state": "completed",
|
||||
"segments": [
|
||||
{
|
||||
"segment_id": "seg-01",
|
||||
"source_pass_id": "pass-01",
|
||||
"commanded_duration_s": 1200,
|
||||
"actual_duration_s": 1203.5,
|
||||
"result_state": "completed",
|
||||
"commanded": {
|
||||
"force_n": 45.0,
|
||||
"table_rpm": 4.0,
|
||||
"spindle_rpm": 40.0,
|
||||
"cam_amplitude_deg": 31.3,
|
||||
"cam_offset_deg": 0.0
|
||||
},
|
||||
"actual": {
|
||||
"force_n_mean": 44.7,
|
||||
"force_n_min": 41.2,
|
||||
"force_n_max": 49.8,
|
||||
"table_rpm_mean": 3.98,
|
||||
"spindle_rpm_mean": 39.9
|
||||
},
|
||||
"pause_windows": [],
|
||||
"anomaly_flags": [],
|
||||
"notes": "Clean run. Minor force excursion at arm reversal points."
|
||||
}
|
||||
],
|
||||
"commanded_summary": {
|
||||
"force_n": 45.0,
|
||||
"table_rpm": 4.0,
|
||||
"spindle_rpm": 40.0
|
||||
},
|
||||
"actual_summary": {
|
||||
"force_n_mean": 44.7,
|
||||
"force_n_min": 41.2,
|
||||
"force_n_max": 49.8,
|
||||
"table_rpm_mean": 3.98,
|
||||
"spindle_rpm_mean": 39.9
|
||||
},
|
||||
"alarms": [],
|
||||
"events": [
|
||||
{
|
||||
"timestamp": "2026-07-17T14:00:00Z",
|
||||
"type": "run_started",
|
||||
"detail": "Operator acknowledged start."
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-07-17T14:20:35Z",
|
||||
"type": "run_completed",
|
||||
"detail": "All segments completed normally."
|
||||
}
|
||||
],
|
||||
"telemetry_ref": "telemetry-run-2026-07-001.csv",
|
||||
"operator_notes": "Smooth run. No intervention needed."
|
||||
}
|
||||
158
shared/schemas/job.schema.json
Normal file
158
shared/schemas/job.schema.json
Normal file
@@ -0,0 +1,158 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://polisher-suite.local/schemas/job.schema.json",
|
||||
"title": "Polisher Job Package",
|
||||
"description": "Frozen planning artifact emitted by polisher-sim. Represents planning truth.",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"schema_version",
|
||||
"job_id",
|
||||
"mirror_id",
|
||||
"machine_family",
|
||||
"planner_version",
|
||||
"created_at",
|
||||
"strategy_summary",
|
||||
"passes"
|
||||
],
|
||||
"properties": {
|
||||
"schema_version": {
|
||||
"type": "string",
|
||||
"const": "job.v1"
|
||||
},
|
||||
"job_id": {
|
||||
"type": "string",
|
||||
"description": "Stable unique identifier for this job."
|
||||
},
|
||||
"mirror_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"machine_family": {
|
||||
"type": "string",
|
||||
"description": "Target machine family (e.g. swing-arm)."
|
||||
},
|
||||
"source_map_id": {
|
||||
"type": "string",
|
||||
"description": "Reference to the input surface measurement."
|
||||
},
|
||||
"target_id": {
|
||||
"type": "string",
|
||||
"description": "Reference to the target surface specification."
|
||||
},
|
||||
"created_at": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
},
|
||||
"created_by": {
|
||||
"type": "string"
|
||||
},
|
||||
"planner_version": {
|
||||
"type": "string",
|
||||
"description": "Software version of polisher-sim that generated this job."
|
||||
},
|
||||
"calibration_state_ref": {
|
||||
"type": "string",
|
||||
"description": "Reference to the calibration state used during planning."
|
||||
},
|
||||
"strategy_summary": {
|
||||
"type": "object",
|
||||
"required": ["intent"],
|
||||
"properties": {
|
||||
"intent": { "type": "string" },
|
||||
"confidence": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 1
|
||||
},
|
||||
"notes": { "type": "string" }
|
||||
}
|
||||
},
|
||||
"passes": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"$ref": "#/$defs/pass"
|
||||
}
|
||||
},
|
||||
"predicted_outcome": {
|
||||
"type": "object",
|
||||
"description": "Summary of predicted post-polish surface state.",
|
||||
"properties": {
|
||||
"removal_rms_nm": { "type": "number" },
|
||||
"removal_pv_nm": { "type": "number" },
|
||||
"residual_zernikes": {
|
||||
"type": "object",
|
||||
"additionalProperties": { "type": "number" }
|
||||
}
|
||||
}
|
||||
},
|
||||
"uncertainty": {
|
||||
"type": "object",
|
||||
"description": "Planner's uncertainty estimates.",
|
||||
"properties": {
|
||||
"removal_rms_nm_range": {
|
||||
"type": "array",
|
||||
"items": { "type": "number" },
|
||||
"minItems": 2,
|
||||
"maxItems": 2
|
||||
},
|
||||
"notes": { "type": "string" }
|
||||
}
|
||||
},
|
||||
"attachments": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": ["filename", "role"],
|
||||
"properties": {
|
||||
"filename": { "type": "string" },
|
||||
"role": { "type": "string" },
|
||||
"description": { "type": "string" }
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"$defs": {
|
||||
"pass": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"pass_id",
|
||||
"sequence_index",
|
||||
"duration_s",
|
||||
"force_n",
|
||||
"table_rpm",
|
||||
"spindle_rpm",
|
||||
"motion_family"
|
||||
],
|
||||
"properties": {
|
||||
"pass_id": { "type": "string" },
|
||||
"sequence_index": { "type": "integer", "minimum": 1 },
|
||||
"objective": { "type": "string" },
|
||||
"preset_name": { "type": "string" },
|
||||
"duration_s": { "type": "number", "minimum": 0 },
|
||||
"force_n": { "type": "number", "minimum": 0 },
|
||||
"table_rpm": { "type": "number", "minimum": 0 },
|
||||
"spindle_rpm": { "type": "number", "minimum": 0 },
|
||||
"motion_family": { "type": "string" },
|
||||
"motion_params": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
},
|
||||
"zone": { "type": "string" },
|
||||
"dither_profile": { "type": "string" },
|
||||
"force_modulation": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"harmonic": { "type": "integer" },
|
||||
"amplitude_n": { "type": "number" },
|
||||
"phase_deg": { "type": "number" }
|
||||
}
|
||||
},
|
||||
"acceptance": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
},
|
||||
"notes": { "type": "string" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
135
shared/schemas/machine-capabilities.schema.json
Normal file
135
shared/schemas/machine-capabilities.schema.json
Normal file
@@ -0,0 +1,135 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://polisher-suite.local/schemas/machine-capabilities.schema.json",
|
||||
"title": "Machine Capabilities",
|
||||
"description": "Conservative declaration of what a machine+controller can safely execute. Unknown capabilities must be explicitly marked rather than assumed.",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"schema_version",
|
||||
"machine_id",
|
||||
"machine_family",
|
||||
"controller_version",
|
||||
"supported_motion_families",
|
||||
"force_range_n",
|
||||
"table_rpm_range",
|
||||
"spindle_rpm_range"
|
||||
],
|
||||
"properties": {
|
||||
"schema_version": {
|
||||
"type": "string",
|
||||
"const": "machine-capabilities.v1"
|
||||
},
|
||||
"machine_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"machine_family": {
|
||||
"type": "string"
|
||||
},
|
||||
"machine_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"controller_version": {
|
||||
"type": "string"
|
||||
},
|
||||
"last_verified": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "When these capabilities were last confirmed on the real machine."
|
||||
},
|
||||
"supported_motion_families": {
|
||||
"type": "array",
|
||||
"items": { "type": "string" },
|
||||
"minItems": 1
|
||||
},
|
||||
"force_range_n": {
|
||||
"$ref": "#/$defs/range_or_unknown"
|
||||
},
|
||||
"table_rpm_range": {
|
||||
"$ref": "#/$defs/range_or_unknown"
|
||||
},
|
||||
"spindle_rpm_range": {
|
||||
"$ref": "#/$defs/range_or_unknown"
|
||||
},
|
||||
"cam_amplitude_range_deg": {
|
||||
"$ref": "#/$defs/range_or_unknown"
|
||||
},
|
||||
"cam_offset_range_deg": {
|
||||
"$ref": "#/$defs/range_or_unknown"
|
||||
},
|
||||
"force_modulation": {
|
||||
"type": "object",
|
||||
"description": "Force modulation capabilities. Omit entirely if unknown.",
|
||||
"properties": {
|
||||
"supported": { "type": "boolean" },
|
||||
"max_harmonics": { "type": "integer" },
|
||||
"max_amplitude_n": { "type": "number" },
|
||||
"notes": { "type": "string" }
|
||||
}
|
||||
},
|
||||
"supported_dither_profiles": {
|
||||
"type": "array",
|
||||
"items": { "type": "string" },
|
||||
"description": "List of dither profile names the controller can handle. Empty = none supported."
|
||||
},
|
||||
"segment_duration_limits": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"min_s": { "type": "number" },
|
||||
"max_s": { "type": "number" }
|
||||
}
|
||||
},
|
||||
"pause_resume_support": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"telemetry_channels": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": ["name", "unit"],
|
||||
"properties": {
|
||||
"name": { "type": "string" },
|
||||
"unit": { "type": "string" },
|
||||
"sample_rate_hz": { "type": "number" },
|
||||
"notes": { "type": "string" }
|
||||
}
|
||||
}
|
||||
},
|
||||
"safety_limits": {
|
||||
"type": "object",
|
||||
"description": "Hard safety limits that the controller enforces regardless of job requests.",
|
||||
"properties": {
|
||||
"max_force_n": { "type": "number" },
|
||||
"max_table_rpm": { "type": "number" },
|
||||
"max_spindle_rpm": { "type": "number" },
|
||||
"notes": { "type": "string" }
|
||||
}
|
||||
},
|
||||
"known_constraints": {
|
||||
"type": "array",
|
||||
"items": { "type": "string" },
|
||||
"description": "Free-text list of known limitations, quirks, or warnings."
|
||||
},
|
||||
"unknowns": {
|
||||
"type": "array",
|
||||
"items": { "type": "string" },
|
||||
"description": "Capabilities that have NOT been verified. Explicit unknowns prevent fake certainty."
|
||||
}
|
||||
},
|
||||
"$defs": {
|
||||
"range_or_unknown": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "array",
|
||||
"items": { "type": "number" },
|
||||
"minItems": 2,
|
||||
"maxItems": 2,
|
||||
"description": "[min, max] range."
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"const": "unknown"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
76
shared/schemas/manifest.schema.json
Normal file
76
shared/schemas/manifest.schema.json
Normal file
@@ -0,0 +1,76 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://polisher-suite.local/schemas/manifest.schema.json",
|
||||
"title": "Artifact Bundle Manifest",
|
||||
"description": "Manifest for a portable artifact bundle. Lists all files with hashes for integrity verification.",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"schema_version",
|
||||
"manifest_id",
|
||||
"bundle_type",
|
||||
"created_at",
|
||||
"entries"
|
||||
],
|
||||
"properties": {
|
||||
"schema_version": {
|
||||
"type": "string",
|
||||
"const": "manifest.v1"
|
||||
},
|
||||
"manifest_id": {
|
||||
"type": "string",
|
||||
"description": "Unique identifier for this manifest."
|
||||
},
|
||||
"bundle_type": {
|
||||
"type": "string",
|
||||
"enum": ["job", "controller-job", "run-log"],
|
||||
"description": "What kind of artifact bundle this manifest describes."
|
||||
},
|
||||
"source_id": {
|
||||
"type": "string",
|
||||
"description": "The primary artifact ID (job_id, controller_job_id, or run_id)."
|
||||
},
|
||||
"created_at": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
},
|
||||
"created_by": {
|
||||
"type": "string",
|
||||
"description": "Software/version that created this bundle."
|
||||
},
|
||||
"entries": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": ["filename", "role", "hash_sha256"],
|
||||
"properties": {
|
||||
"filename": {
|
||||
"type": "string",
|
||||
"description": "Relative path within the bundle."
|
||||
},
|
||||
"role": {
|
||||
"type": "string",
|
||||
"description": "Semantic role: primary, attachment, telemetry, report, etc."
|
||||
},
|
||||
"hash_sha256": {
|
||||
"type": "string",
|
||||
"pattern": "^[a-f0-9]{64}$"
|
||||
},
|
||||
"size_bytes": {
|
||||
"type": "integer",
|
||||
"minimum": 0
|
||||
},
|
||||
"content_type": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"notes": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
171
shared/schemas/run-log.schema.json
Normal file
171
shared/schemas/run-log.schema.json
Normal file
@@ -0,0 +1,171 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://polisher-suite.local/schemas/run-log.schema.json",
|
||||
"title": "Run Log",
|
||||
"description": "Canonical execution record emitted by polisher-control. Represents executed truth.",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"schema_version",
|
||||
"run_id",
|
||||
"job_id",
|
||||
"controller_job_id",
|
||||
"controller_version",
|
||||
"machine_id",
|
||||
"started_at",
|
||||
"ended_at",
|
||||
"result_state",
|
||||
"segments"
|
||||
],
|
||||
"properties": {
|
||||
"schema_version": {
|
||||
"type": "string",
|
||||
"const": "run-log.v1"
|
||||
},
|
||||
"run_id": {
|
||||
"type": "string",
|
||||
"description": "Stable unique identifier for this execution run."
|
||||
},
|
||||
"job_id": {
|
||||
"type": "string",
|
||||
"description": "Back-reference to the source planning job."
|
||||
},
|
||||
"controller_job_id": {
|
||||
"type": "string",
|
||||
"description": "Back-reference to the translated controller-job package."
|
||||
},
|
||||
"controller_version": {
|
||||
"type": "string"
|
||||
},
|
||||
"machine_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"started_at": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
},
|
||||
"ended_at": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
},
|
||||
"result_state": {
|
||||
"type": "string",
|
||||
"enum": ["completed", "completed_with_pause", "aborted", "faulted"]
|
||||
},
|
||||
"segments": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"$ref": "#/$defs/executed_segment"
|
||||
}
|
||||
},
|
||||
"commanded_summary": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"force_n": { "type": "number" },
|
||||
"table_rpm": { "type": "number" },
|
||||
"spindle_rpm": { "type": "number" }
|
||||
}
|
||||
},
|
||||
"actual_summary": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"force_n_mean": { "type": "number" },
|
||||
"force_n_min": { "type": "number" },
|
||||
"force_n_max": { "type": "number" },
|
||||
"table_rpm_mean": { "type": "number" },
|
||||
"spindle_rpm_mean": { "type": "number" }
|
||||
}
|
||||
},
|
||||
"alarms": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": ["timestamp", "code", "message"],
|
||||
"properties": {
|
||||
"timestamp": { "type": "string", "format": "date-time" },
|
||||
"code": { "type": "string" },
|
||||
"message": { "type": "string" },
|
||||
"severity": { "type": "string", "enum": ["info", "warning", "critical"] }
|
||||
}
|
||||
}
|
||||
},
|
||||
"events": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": ["timestamp", "type"],
|
||||
"properties": {
|
||||
"timestamp": { "type": "string", "format": "date-time" },
|
||||
"type": { "type": "string" },
|
||||
"detail": { "type": "string" }
|
||||
}
|
||||
}
|
||||
},
|
||||
"telemetry_ref": {
|
||||
"type": "string",
|
||||
"description": "Filename or path to the raw telemetry data file."
|
||||
},
|
||||
"operator_notes": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"$defs": {
|
||||
"executed_segment": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"segment_id",
|
||||
"source_pass_id",
|
||||
"commanded_duration_s",
|
||||
"actual_duration_s",
|
||||
"result_state"
|
||||
],
|
||||
"properties": {
|
||||
"segment_id": { "type": "string" },
|
||||
"source_pass_id": { "type": "string" },
|
||||
"commanded_duration_s": { "type": "number" },
|
||||
"actual_duration_s": { "type": "number" },
|
||||
"result_state": {
|
||||
"type": "string",
|
||||
"enum": ["completed", "completed_with_pause", "aborted", "faulted", "skipped"]
|
||||
},
|
||||
"commanded": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"force_n": { "type": "number" },
|
||||
"table_rpm": { "type": "number" },
|
||||
"spindle_rpm": { "type": "number" },
|
||||
"cam_amplitude_deg": { "type": "number" },
|
||||
"cam_offset_deg": { "type": "number" }
|
||||
}
|
||||
},
|
||||
"actual": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"force_n_mean": { "type": "number" },
|
||||
"force_n_min": { "type": "number" },
|
||||
"force_n_max": { "type": "number" },
|
||||
"table_rpm_mean": { "type": "number" },
|
||||
"spindle_rpm_mean": { "type": "number" }
|
||||
}
|
||||
},
|
||||
"pause_windows": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": ["paused_at", "resumed_at"],
|
||||
"properties": {
|
||||
"paused_at": { "type": "string", "format": "date-time" },
|
||||
"resumed_at": { "type": "string", "format": "date-time" },
|
||||
"reason": { "type": "string" }
|
||||
}
|
||||
}
|
||||
},
|
||||
"anomaly_flags": {
|
||||
"type": "array",
|
||||
"items": { "type": "string" }
|
||||
},
|
||||
"notes": { "type": "string" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user