{
  "schema_version": 1,
  "id": "duskcoil-lab-pilot",
  "version": "1.0.0",
  "license": "unspecified",
  "environment": {
    "local_tested": {
      "python": "3.12.3",
      "numpy": "1.26.4"
    },
    "browser_tested": {
      "python": "3.14.2",
      "numpy": "2.4.6",
      "pyodide": "314.0.6"
    },
    "hardware": {
      "required": "CPU only; no GPU or physical sensor",
      "reference": "WSL/Linux x86_64; timings are environment-specific, not acceptance metrics"
    },
    "plotting_only": {
      "matplotlib": "3.6.3"
    }
  },
  "artifacts": [
    {
      "id": "src/pid_lab.py",
      "path": "src/pid_lab.py",
      "kind": "source",
      "source_path": "content/uploads/labs/pid_lab.py",
      "sha256": "42d2efa18cb50a7a8558cde7e08b62bf559f244e001ccb5f45187e5268e1c404",
      "bytes": 2146,
      "description": "Original normalized PID simulation",
      "license": "unspecified",
      "url": "/uploads/labs/pid_lab.py",
      "language": "python"
    },
    {
      "id": "src/kernels.py",
      "path": "src/kernels.py",
      "kind": "source",
      "source_path": "content/uploads/labs/playground/kernels.py",
      "sha256": "a7cdc7032ba027be9e56b002e098abb0dc631dbf82f473e4257579a7417b3177",
      "bytes": 6167,
      "description": "Generated Kalman/ICP computation",
      "license": "unspecified",
      "url": "/uploads/labs/playground/kernels.py",
      "generated_from": [
        "originals/engineering_labs.py",
        "originals/build_playground_sources.py",
        "data/kalman_baseline.csv"
      ],
      "language": "python"
    },
    {
      "id": "src/experiment.py",
      "path": "src/experiment.py",
      "kind": "source",
      "source_path": "content/uploads/labs/playground/experiment.py",
      "sha256": "110329c72ca9006b7e0f845da612a0f697746d796240e403c1a36bdb7cf0dd0a",
      "bytes": 3402,
      "description": "Shared browser/local adapter",
      "license": "unspecified",
      "url": "/uploads/labs/playground/experiment.py",
      "language": "python"
    },
    {
      "id": "originals/engineering_labs.py",
      "path": "originals/engineering_labs.py",
      "kind": "source",
      "source_path": "content/uploads/labs/expansion/engineering_labs.py",
      "sha256": "f9432925e730a68ca265e2fbcceb34c1d9531fede9126b073452d5ee178076fd",
      "bytes": 8631,
      "description": "Original multi-experiment and figure generator",
      "license": "unspecified",
      "url": "/uploads/labs/expansion/engineering_labs.py",
      "language": "python"
    },
    {
      "id": "originals/build_playground_sources.py",
      "path": "originals/build_playground_sources.py",
      "kind": "source",
      "source_path": "tools/build_playground_sources.py",
      "sha256": "85c97a591789feeafeebd1b519499832fcc0eaa998642305e6bcf716627ebcd3",
      "bytes": 2220,
      "description": "AST generator; runs from repository checkout",
      "license": "unspecified",
      "language": "python"
    },
    {
      "id": "reproduce.py",
      "path": "reproduce.py",
      "kind": "source",
      "source_path": "tools/artifact_templates/reproduce.py",
      "sha256": "239acd3e23f4b525a6d8a783abfbf3c2a84e21da84750876abf63e82cdb2e2d3",
      "bytes": 4346,
      "description": "Package reproduce.py",
      "license": "unspecified",
      "language": "python"
    },
    {
      "id": "README.md",
      "path": "README.md",
      "kind": "documentation",
      "source_path": "tools/artifact_templates/README.md",
      "sha256": "d0d98e9822bb02f8a53df48d702f9037603daf80efb642f05a62c0ef2eba100f",
      "bytes": 3733,
      "description": "Package README.md",
      "license": "unspecified"
    },
    {
      "id": "requirements.txt",
      "path": "requirements.txt",
      "kind": "config",
      "source_path": "tools/artifact_templates/requirements.txt",
      "sha256": "8cbd2cf157156c8febd86a6b377e1a67aa920258bb608bce287a0ffb74b90e1a",
      "bytes": 94,
      "description": "Package requirements.txt",
      "license": "unspecified"
    },
    {
      "id": "data/pid-results.csv",
      "path": "data/pid-results.csv",
      "kind": "output",
      "source_path": "content/uploads/labs/pid-results.csv",
      "sha256": "9f5c5c575f91aeb7a3b07cf8cc516228ad450d3bb8ee13cda8e7013f8496d997",
      "bytes": 730788,
      "description": "Saved synthetic PID reference",
      "license": "unspecified",
      "url": "/uploads/labs/pid-results.csv",
      "data_type": "synthetic",
      "generated_from": [
        "src/pid_lab.py"
      ],
      "columns": [
        "scenario",
        "time_s",
        "target",
        "output",
        "control",
        "integral"
      ],
      "rows": 9604,
      "missing_value": "none"
    },
    {
      "id": "data/pid-summary.json",
      "path": "data/pid-summary.json",
      "kind": "output",
      "source_path": "content/uploads/labs/pid-summary.json",
      "sha256": "45ea7e0fae9693f6adebe79dc4fc02412600c182c7c5ea56175544fca6d54057",
      "bytes": 566,
      "description": "Saved synthetic PID reference",
      "license": "unspecified",
      "url": "/uploads/labs/pid-summary.json",
      "data_type": "synthetic",
      "generated_from": [
        "src/pid_lab.py"
      ]
    },
    {
      "id": "data/engineering-results.json",
      "path": "data/engineering-results.json",
      "kind": "output",
      "source_path": "content/uploads/labs/expansion/engineering-results.json",
      "sha256": "ecfc8268c598da514cd7f2f0bb67476ba32d4a6ab6f4ce472e73f2bd3dbfdf73",
      "bytes": 2058,
      "description": "Saved synthetic reference; units in column/metric names",
      "license": "unspecified",
      "url": "/uploads/labs/expansion/engineering-results.json",
      "data_type": "synthetic",
      "generated_from": [
        "originals/engineering_labs.py"
      ]
    },
    {
      "id": "data/icp_bad_init.csv",
      "path": "data/icp_bad_init.csv",
      "kind": "output",
      "source_path": "content/uploads/labs/expansion/icp_bad_init.csv",
      "sha256": "12cfe93306fd9ec1e102afc81f59ee3b5e29871b8ed24451a1b149843ef62abf",
      "bytes": 5347,
      "description": "Saved synthetic reference; units in column/metric names",
      "license": "unspecified",
      "url": "/uploads/labs/expansion/icp_bad_init.csv",
      "data_type": "synthetic",
      "generated_from": [
        "originals/engineering_labs.py"
      ],
      "columns": [
        "source_x_m",
        "source_y_m",
        "aligned_x_m",
        "aligned_y_m"
      ],
      "rows": 102,
      "missing_value": "none"
    },
    {
      "id": "data/icp_good_init.csv",
      "path": "data/icp_good_init.csv",
      "kind": "output",
      "source_path": "content/uploads/labs/expansion/icp_good_init.csv",
      "sha256": "3d6861896a6c1828cd4cf37c610b9239c91f0afb30755fac9bd23f54288299d4",
      "bytes": 5480,
      "description": "Saved synthetic reference; units in column/metric names",
      "license": "unspecified",
      "url": "/uploads/labs/expansion/icp_good_init.csv",
      "data_type": "synthetic",
      "generated_from": [
        "originals/engineering_labs.py"
      ],
      "columns": [
        "source_x_m",
        "source_y_m",
        "aligned_x_m",
        "aligned_y_m"
      ],
      "rows": 102,
      "missing_value": "none"
    },
    {
      "id": "data/icp_outliers_gated.csv",
      "path": "data/icp_outliers_gated.csv",
      "kind": "output",
      "source_path": "content/uploads/labs/expansion/icp_outliers_gated.csv",
      "sha256": "593f60e920e92765adc651a3a490f874ced9a3f758153028aa4dd5b5b29aa23f",
      "bytes": 6594,
      "description": "Saved synthetic reference; units in column/metric names",
      "license": "unspecified",
      "url": "/uploads/labs/expansion/icp_outliers_gated.csv",
      "data_type": "synthetic",
      "generated_from": [
        "originals/engineering_labs.py"
      ],
      "columns": [
        "source_x_m",
        "source_y_m",
        "aligned_x_m",
        "aligned_y_m"
      ],
      "rows": 132,
      "missing_value": "none"
    },
    {
      "id": "data/icp_outliers_open.csv",
      "path": "data/icp_outliers_open.csv",
      "kind": "output",
      "source_path": "content/uploads/labs/expansion/icp_outliers_open.csv",
      "sha256": "f6a244956b10422c546c129483d058228505755860a9c44224062c532e3e577e",
      "bytes": 6525,
      "description": "Saved synthetic reference; units in column/metric names",
      "license": "unspecified",
      "url": "/uploads/labs/expansion/icp_outliers_open.csv",
      "data_type": "synthetic",
      "generated_from": [
        "originals/engineering_labs.py"
      ],
      "columns": [
        "source_x_m",
        "source_y_m",
        "aligned_x_m",
        "aligned_y_m"
      ],
      "rows": 132,
      "missing_value": "none"
    },
    {
      "id": "data/icp_symmetric_ring.csv",
      "path": "data/icp_symmetric_ring.csv",
      "kind": "output",
      "source_path": "content/uploads/labs/expansion/icp_symmetric_ring.csv",
      "sha256": "90658cd250481170783ed51c155055991fb0006ec245517a36069fd6781fa40a",
      "bytes": 6272,
      "description": "Saved synthetic reference; units in column/metric names",
      "license": "unspecified",
      "url": "/uploads/labs/expansion/icp_symmetric_ring.csv",
      "data_type": "synthetic",
      "generated_from": [
        "originals/engineering_labs.py"
      ],
      "columns": [
        "source_x_m",
        "source_y_m",
        "aligned_x_m",
        "aligned_y_m"
      ],
      "rows": 120,
      "missing_value": "none"
    },
    {
      "id": "data/icp_target.csv",
      "path": "data/icp_target.csv",
      "kind": "dataset",
      "source_path": "content/uploads/labs/expansion/icp_target.csv",
      "sha256": "8176d248bae87fbd1ba51e14c68fe582ea796ed57f75676bc9e64e6f4585be57",
      "bytes": 656,
      "description": "Saved synthetic reference; units in column/metric names",
      "license": "unspecified",
      "url": "/uploads/labs/expansion/icp_target.csv",
      "data_type": "synthetic",
      "generated_from": [
        "originals/engineering_labs.py"
      ],
      "columns": [
        "x_m",
        "y_m"
      ],
      "rows": 102,
      "missing_value": "none"
    },
    {
      "id": "data/kalman_baseline.csv",
      "path": "data/kalman_baseline.csv",
      "kind": "dataset",
      "source_path": "content/uploads/labs/expansion/kalman_baseline.csv",
      "sha256": "acc07a2de3a76642aac13634ad88d7b411c748fcf62fddabdda0e3cd8f510daa",
      "bytes": 13685,
      "description": "Saved synthetic reference; units in column/metric names",
      "license": "unspecified",
      "url": "/uploads/labs/expansion/kalman_baseline.csv",
      "data_type": "synthetic",
      "generated_from": [
        "originals/engineering_labs.py"
      ],
      "columns": [
        "time_s",
        "truth_m",
        "measurement_m",
        "estimate_m",
        "sigma_m"
      ],
      "rows": 300,
      "missing_value": "nan"
    },
    {
      "id": "data/kalman_gated.csv",
      "path": "data/kalman_gated.csv",
      "kind": "output",
      "source_path": "content/uploads/labs/expansion/kalman_gated.csv",
      "sha256": "8d418c7e463d347493444cda74e816d080c4c8a43ec97f342f24f31b9dd49e1d",
      "bytes": 13684,
      "description": "Saved synthetic reference; units in column/metric names",
      "license": "unspecified",
      "url": "/uploads/labs/expansion/kalman_gated.csv",
      "data_type": "synthetic",
      "generated_from": [
        "originals/engineering_labs.py"
      ],
      "columns": [
        "time_s",
        "truth_m",
        "measurement_m",
        "estimate_m",
        "sigma_m"
      ],
      "rows": 300,
      "missing_value": "nan"
    },
    {
      "id": "data/kalman_small_Q.csv",
      "path": "data/kalman_small_Q.csv",
      "kind": "output",
      "source_path": "content/uploads/labs/expansion/kalman_small_Q.csv",
      "sha256": "41f0196fb39abf59c294597aa29a7ba5ed677cb59bcbb9cb9732928357714334",
      "bytes": 13692,
      "description": "Saved synthetic reference; units in column/metric names",
      "license": "unspecified",
      "url": "/uploads/labs/expansion/kalman_small_Q.csv",
      "data_type": "synthetic",
      "generated_from": [
        "originals/engineering_labs.py"
      ],
      "columns": [
        "time_s",
        "truth_m",
        "measurement_m",
        "estimate_m",
        "sigma_m"
      ],
      "rows": 300,
      "missing_value": "nan"
    },
    {
      "id": "data/kalman_small_R.csv",
      "path": "data/kalman_small_R.csv",
      "kind": "output",
      "source_path": "content/uploads/labs/expansion/kalman_small_R.csv",
      "sha256": "9ebc45e5cd0ac61d697c33da42ab4500ccc93e8242dcba445427436ecf02798e",
      "bytes": 13613,
      "description": "Saved synthetic reference; units in column/metric names",
      "license": "unspecified",
      "url": "/uploads/labs/expansion/kalman_small_R.csv",
      "data_type": "synthetic",
      "generated_from": [
        "originals/engineering_labs.py"
      ],
      "columns": [
        "time_s",
        "truth_m",
        "measurement_m",
        "estimate_m",
        "sigma_m"
      ],
      "rows": 300,
      "missing_value": "nan"
    },
    {
      "id": "figures/pid-response.svg",
      "path": "figures/pid-response.svg",
      "kind": "output",
      "source_path": "content/uploads/labs/pid-response.svg",
      "sha256": "29dd6163aae0cca0a995c207163c250d65488c409bd9db4871e0480e98120bf9",
      "bytes": 69225,
      "description": "Existing static synthetic result figure",
      "license": "unspecified",
      "url": "/uploads/labs/pid-response.svg",
      "data_type": "synthetic"
    },
    {
      "id": "figures/kalman.svg",
      "path": "figures/kalman.svg",
      "kind": "output",
      "source_path": "content/uploads/labs/expansion/kalman.svg",
      "sha256": "e1df89a8f8e7e411a6b2e9ae8e3ad0753648ba903975f184fa935c5b07040644",
      "bytes": 77487,
      "description": "Existing static synthetic result figure",
      "license": "unspecified",
      "url": "/uploads/labs/expansion/kalman.svg",
      "data_type": "synthetic"
    },
    {
      "id": "figures/icp.svg",
      "path": "figures/icp.svg",
      "kind": "output",
      "source_path": "content/uploads/labs/expansion/icp.svg",
      "sha256": "c1e70ffca67905d9c5b52fb44c6602bc15510b8baf9acd6958cc9246ca7d5379",
      "bytes": 162998,
      "description": "Existing static synthetic result figure",
      "license": "unspecified",
      "url": "/uploads/labs/expansion/icp.svg",
      "data_type": "synthetic"
    }
  ],
  "experiments": {
    "pid": {
      "content_id": "control-pid-lab",
      "technology_unit": "pid",
      "data_type": "synthetic",
      "seed": {
        "value": null,
        "policy": "Deterministic; no random draw"
      },
      "parameters": {
        "kp": {
          "type": "number",
          "min": 0,
          "max": 10,
          "default": 3,
          "unit": "normalized"
        },
        "ki": {
          "type": "number",
          "min": 0,
          "max": 10,
          "default": 2,
          "unit": "normalized"
        },
        "kd": {
          "type": "number",
          "min": 0,
          "max": 5,
          "default": 1,
          "unit": "normalized"
        },
        "delay": {
          "type": "number",
          "min": 0,
          "max": 1,
          "default": 0,
          "unit": "s",
          "step": 0.005
        },
        "limit": {
          "type": "number",
          "min": 0.1,
          "max": 5,
          "default": 3,
          "unit": "normalized"
        },
        "antiwindup": {
          "type": "boolean",
          "default": true
        }
      },
      "fixed_parameters": {
        "dt_s": 0.005,
        "duration_s": 12,
        "initial_state": [
          0,
          0
        ],
        "target_before_6s": 1,
        "target_from_6s": 0.4,
        "plant": "y_ddot + 2*y_dot + y = u; semi-implicit Euler; normalized signals"
      },
      "metrics": {
        "IAE_0_12s": "normalized*s",
        "output_at_6s": "normalized",
        "output_at_12s": "normalized"
      },
      "comparison": {
        "atol": 2e-07,
        "rtol": 1e-08
      },
      "source_ids": [
        "src/pid_lab.py",
        "src/experiment.py"
      ],
      "runtime_adapters": {
        "local": {
          "language": "python",
          "entrypoint": "reproduce.py"
        },
        "browser": {
          "runtime": "python",
          "runtime_bundle": "pyodide-314.0.6",
          "definition_url": "/assets/playground/definitions.json",
          "source_hashes": [
            {
              "path": "/uploads/labs/pid_lab.py",
              "sha256": "42d2efa18cb50a7a8558cde7e08b62bf559f244e001ccb5f45187e5268e1c404"
            },
            {
              "path": "/uploads/labs/playground/experiment.py",
              "sha256": "110329c72ca9006b7e0f845da612a0f697746d796240e403c1a36bdb7cf0dd0a"
            }
          ]
        }
      },
      "cases": [
        {
          "id": "nominal",
          "parameters": {
            "kp": 3,
            "ki": 2,
            "kd": 1,
            "delay": 0,
            "limit": 3,
            "antiwindup": true
          },
          "expected_metrics": {
            "output_at_6s": 0.9987378952805225,
            "output_at_12s": 0.4007563087772777,
            "IAE_0_12s": 1.7913335801157528
          },
          "failure_condition": "Reference tracking case"
        },
        {
          "id": "delay_0.4s",
          "parameters": {
            "kp": 3,
            "ki": 2,
            "kd": 1,
            "delay": 0.4,
            "limit": 3,
            "antiwindup": true
          },
          "expected_metrics": {
            "output_at_6s": 1.0113883759404196,
            "output_at_12s": 0.38830599261999976,
            "IAE_0_12s": 1.8860435524831938
          },
          "failure_condition": "Observation delay degrades response"
        },
        {
          "id": "limit_0.8_aw",
          "parameters": {
            "kp": 3,
            "ki": 2,
            "kd": 1,
            "delay": 0,
            "limit": 0.8,
            "antiwindup": true
          },
          "expected_metrics": {
            "output_at_6s": 0.785166273983236,
            "output_at_12s": 0.40034607962324387,
            "IAE_0_12s": 3.342432608013856
          },
          "failure_condition": "Actuator saturation limits tracking"
        },
        {
          "id": "limit_0.8_no_aw",
          "parameters": {
            "kp": 3,
            "ki": 2,
            "kd": 1,
            "delay": 0,
            "limit": 0.8,
            "antiwindup": false
          },
          "expected_metrics": {
            "output_at_6s": 0.7859706442705103,
            "output_at_12s": 0.6601822838922625,
            "IAE_0_12s": 5.0996013262239135
          },
          "failure_condition": "Integral windup with saturation"
        }
      ]
    },
    "kalman": {
      "content_id": "control-kalman-lab",
      "technology_unit": "kalman-filter",
      "data_type": "synthetic",
      "seed": {
        "value": 42,
        "policy": "NumPy default_rng generated original observations; replay frozen CSV values"
      },
      "parameters": {
        "q": {
          "type": "number",
          "min": 0.002,
          "max": 2,
          "default": 0.4,
          "unit": "m²/s⁴"
        },
        "r": {
          "type": "number",
          "min": 0.0049,
          "max": 4,
          "default": 0.49,
          "unit": "m²"
        },
        "gate": {
          "type": "boolean",
          "default": false
        }
      },
      "fixed_parameters": {
        "dt_s": 0.1,
        "samples": 300,
        "initial_state": [
          0,
          1
        ],
        "initial_covariance_diagonal": [
          1,
          1
        ],
        "measurement_sigma_m": 0.7,
        "missing_indices": "70:100 (end exclusive)",
        "outlier_index": 160,
        "outlier_offset_m": 12,
        "gate_squared_innovation": 9,
        "process_noise": "independent acceleration variance q per step, Q=q*g*g.T",
        "observations": "frozen from data/kalman_baseline.csv; 10 significant digits"
      },
      "metrics": {
        "rmse_m": "m",
        "rejected": "count"
      },
      "comparison": {
        "atol": 2e-07,
        "rtol": 1e-08
      },
      "source_ids": [
        "src/kernels.py",
        "src/experiment.py"
      ],
      "runtime_adapters": {
        "local": {
          "language": "python",
          "entrypoint": "reproduce.py"
        },
        "browser": {
          "runtime": "python",
          "runtime_bundle": "pyodide-314.0.6",
          "definition_url": "/assets/playground/definitions.json",
          "source_hashes": [
            {
              "path": "/uploads/labs/playground/kernels.py",
              "sha256": "a7cdc7032ba027be9e56b002e098abb0dc631dbf82f473e4257579a7417b3177"
            },
            {
              "path": "/uploads/labs/playground/experiment.py",
              "sha256": "110329c72ca9006b7e0f845da612a0f697746d796240e403c1a36bdb7cf0dd0a"
            }
          ]
        }
      },
      "cases": [
        {
          "id": "baseline",
          "parameters": {
            "q": 0.4,
            "r": 0.49,
            "gate": false
          },
          "expected_metrics": {
            "rmse_m": 0.26210435405238264,
            "rejected": 0
          },
          "failure_condition": "Missing samples 70:100 and +12 m outlier at index 160"
        },
        {
          "id": "gated",
          "parameters": {
            "q": 0.4,
            "r": 0.49,
            "gate": true
          },
          "expected_metrics": {
            "rmse_m": 0.1776810247485372,
            "rejected": 2
          },
          "failure_condition": "Gate rejects outliers; covariance remains positive semidefinite"
        },
        {
          "id": "small_Q",
          "parameters": {
            "q": 0.002,
            "r": 0.49,
            "gate": true
          },
          "expected_metrics": {
            "rmse_m": 0.3927112546859182,
            "rejected": 4
          },
          "failure_condition": "Underestimated process noise can reject valid motion"
        },
        {
          "id": "small_R",
          "parameters": {
            "q": 0.4,
            "r": 0.0049,
            "gate": true
          },
          "expected_metrics": {
            "rmse_m": 11.250709277649616,
            "rejected": 237
          },
          "failure_condition": "Underestimated measurement noise makes the filter overconfident"
        }
      ]
    },
    "icp": {
      "content_id": "cv-icp-lab",
      "technology_unit": "icp",
      "data_type": "synthetic",
      "seed": {
        "value": null,
        "policy": "Deterministic; no random draw"
      },
      "parameters": {
        "case": {
          "type": "enum",
          "values": [
            "good_init",
            "bad_init",
            "outliers",
            "symmetric_ring"
          ],
          "default": "good_init"
        },
        "threshold": {
          "type": "number",
          "min": 0.01,
          "max": 10,
          "default": 0.5,
          "unit": "m"
        }
      },
      "fixed_parameters": {
        "dimension": 2,
        "max_iterations": 100,
        "convergence_threshold": 1e-10,
        "target": "L: 61 x-axis + 41 y-axis points, including duplicate origin",
        "true_angle_deg": 20,
        "true_translation_m": [
          0.4,
          -0.3
        ],
        "initial_angle_deg": 18,
        "initial_translation_m": [
          0.35,
          -0.25
        ],
        "bad_initial_angle_deg": 110,
        "bad_initial_translation_m": [
          1.5,
          1
        ],
        "outlier_points": 30,
        "ring_points": 120,
        "ring_true_angle_deg": 0,
        "ring_initial_angle_deg": 90,
        "correspondence": "nearest target; distance strictly less than threshold; at least 3 for update"
      },
      "metrics": {
        "inlier_rmse_m": "m",
        "fitness": "fraction",
        "rotation_error_deg": "deg",
        "translation_error_m": "m"
      },
      "comparison": {
        "atol": 2e-07,
        "rtol": 1e-08
      },
      "source_ids": [
        "src/kernels.py",
        "src/experiment.py"
      ],
      "runtime_adapters": {
        "local": {
          "language": "python",
          "entrypoint": "reproduce.py"
        },
        "browser": {
          "runtime": "python",
          "runtime_bundle": "pyodide-314.0.6",
          "definition_url": "/assets/playground/definitions.json",
          "source_hashes": [
            {
              "path": "/uploads/labs/playground/kernels.py",
              "sha256": "a7cdc7032ba027be9e56b002e098abb0dc631dbf82f473e4257579a7417b3177"
            },
            {
              "path": "/uploads/labs/playground/experiment.py",
              "sha256": "110329c72ca9006b7e0f845da612a0f697746d796240e403c1a36bdb7cf0dd0a"
            }
          ]
        }
      },
      "cases": [
        {
          "id": "good_init",
          "parameters": {
            "case": "good_init",
            "threshold": 0.5
          },
          "expected_metrics": {
            "inlier_rmse_m": 0.023372453806877965,
            "fitness": 1.0,
            "rotation_error_deg": 1.2584369446650743,
            "translation_error_m": 0.05479128022759662
          },
          "failure_condition": "Reference alignment with a nearby initial pose"
        },
        {
          "id": "bad_init",
          "parameters": {
            "case": "bad_init",
            "threshold": 0.5
          },
          "expected_metrics": {
            "inlier_rmse_m": 0.1505858873657393,
            "fitness": 0.5392156862745098,
            "rotation_error_deg": 171.69905172990366,
            "translation_error_m": 2.5194742306078326
          },
          "failure_condition": "Poor initialization can converge to a wrong pose"
        },
        {
          "id": "outliers_open",
          "parameters": {
            "case": "outliers",
            "threshold": 10
          },
          "expected_metrics": {
            "inlier_rmse_m": 1.11719399517583,
            "fitness": 1.0,
            "rotation_error_deg": 71.41171879928567,
            "translation_error_m": 2.656979387163232
          },
          "failure_condition": "Open correspondence gate admits distant outliers"
        },
        {
          "id": "outliers_gated",
          "parameters": {
            "case": "outliers",
            "threshold": 0.5
          },
          "expected_metrics": {
            "inlier_rmse_m": 0.023372453806877965,
            "fitness": 0.7727272727272727,
            "rotation_error_deg": 1.2584369446650743,
            "translation_error_m": 0.05479128022759662
          },
          "failure_condition": "Gate excludes outliers; fitness need not be one"
        },
        {
          "id": "symmetric_ring",
          "parameters": {
            "case": "symmetric_ring",
            "threshold": 0.5
          },
          "expected_metrics": {
            "inlier_rmse_m": 3.8118847525843657e-16,
            "fitness": 1.0,
            "rotation_error_deg": 90.0,
            "translation_error_m": 9.990563187536139e-17
          },
          "failure_condition": "Near-zero residual with 90 degree rotation error; pose is ambiguous"
        }
      ]
    }
  },
  "regeneration": [
    "python3 tools/build_playground_sources.py",
    "python3 tools/build_artifacts.py",
    "python3 tools/build_artifacts.py --check"
  ],
  "limitations": [
    "First-party source/data license unspecified; no new reuse license assigned",
    "Synthetic educational data, not measured or a hardware benchmark",
    "No C++ adapter or OpenCV image input in this package",
    "Numerical tolerance, not cross-platform byte-identical computation; compute timing excluded"
  ]
}
