physlint 0.3.1__tar.gz → 0.3.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (175) hide show
  1. physlint-0.3.2/.github/ISSUE_TEMPLATE/evidence-submission.yml +59 -0
  2. {physlint-0.3.1 → physlint-0.3.2}/CHANGELOG.md +7 -0
  3. {physlint-0.3.1 → physlint-0.3.2}/PKG-INFO +11 -9
  4. {physlint-0.3.1 → physlint-0.3.2}/README.md +10 -8
  5. physlint-0.3.2/docs/assets/launch/exports/evidence-index.png +0 -0
  6. {physlint-0.3.1 → physlint-0.3.2}/docs/metrics/downloads.json +2 -2
  7. {physlint-0.3.1 → physlint-0.3.2}/observatory/README.md +2 -2
  8. {physlint-0.3.1 → physlint-0.3.2}/observatory/app/ObservatoryTable.tsx +7 -6
  9. {physlint-0.3.1 → physlint-0.3.2}/observatory/app/globals.css +28 -3
  10. physlint-0.3.2/observatory/app/page.tsx +168 -0
  11. {physlint-0.3.1 → physlint-0.3.2}/observatory/data/observations.json +100 -15
  12. {physlint-0.3.1 → physlint-0.3.2}/observatory/tests/rendered-html.test.mjs +5 -3
  13. {physlint-0.3.1 → physlint-0.3.2}/pyproject.toml +1 -1
  14. {physlint-0.3.1 → physlint-0.3.2}/src/physlint/_version.py +1 -1
  15. {physlint-0.3.1 → physlint-0.3.2}/tests/test_cli.py +1 -1
  16. {physlint-0.3.1 → physlint-0.3.2}/tests/test_report.py +1 -1
  17. {physlint-0.3.1 → physlint-0.3.2}/uv.lock +1 -1
  18. {physlint-0.3.1 → physlint-0.3.2}/validation/build_observatory.py +71 -19
  19. {physlint-0.3.1 → physlint-0.3.2}/validation/manifest.yaml +1 -1
  20. {physlint-0.3.1 → physlint-0.3.2}/validation/mcap_manifest.yaml +1 -1
  21. {physlint-0.3.1 → physlint-0.3.2}/validation/survey_manifest.yaml +1 -1
  22. physlint-0.3.1/observatory/app/ComparisonTable.tsx +0 -56
  23. physlint-0.3.1/observatory/app/page.tsx +0 -101
  24. {physlint-0.3.1 → physlint-0.3.2}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  25. {physlint-0.3.1 → physlint-0.3.2}/.github/ISSUE_TEMPLATE/false-positive.yml +0 -0
  26. {physlint-0.3.1 → physlint-0.3.2}/.github/ISSUE_TEMPLATE/format-request.yml +0 -0
  27. {physlint-0.3.1 → physlint-0.3.2}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  28. {physlint-0.3.1 → physlint-0.3.2}/.github/scripts/update_download_metrics.py +0 -0
  29. {physlint-0.3.1 → physlint-0.3.2}/.github/workflows/ci.yml +0 -0
  30. {physlint-0.3.1 → physlint-0.3.2}/.github/workflows/download-metrics.yml +0 -0
  31. {physlint-0.3.1 → physlint-0.3.2}/.github/workflows/publish-testpypi.yml +0 -0
  32. {physlint-0.3.1 → physlint-0.3.2}/.github/workflows/publish.yml +0 -0
  33. {physlint-0.3.1 → physlint-0.3.2}/.github/workflows/real-data-validation.yml +0 -0
  34. {physlint-0.3.1 → physlint-0.3.2}/.gitignore +0 -0
  35. {physlint-0.3.1 → physlint-0.3.2}/CONTRIBUTING.md +0 -0
  36. {physlint-0.3.1 → physlint-0.3.2}/LICENSE +0 -0
  37. {physlint-0.3.1 → physlint-0.3.2}/SECURITY.md +0 -0
  38. {physlint-0.3.1 → physlint-0.3.2}/docs/adapters/lerobot.md +0 -0
  39. {physlint-0.3.1 → physlint-0.3.2}/docs/adapters/mcap-ros2.md +0 -0
  40. {physlint-0.3.1 → physlint-0.3.2}/docs/assets/launch/exports/clean-validation.png +0 -0
  41. {physlint-0.3.1 → physlint-0.3.2}/docs/assets/launch/exports/controlled-nan-failure.png +0 -0
  42. {physlint-0.3.1 → physlint-0.3.2}/docs/assets/launch/exports/format-compatibility.png +0 -0
  43. {physlint-0.3.1 → physlint-0.3.2}/docs/assets/launch/exports/validation-summary.png +0 -0
  44. {physlint-0.3.1 → physlint-0.3.2}/docs/assets/launch/validation-summary.png +0 -0
  45. {physlint-0.3.1 → physlint-0.3.2}/docs/assets/launch/validation-summary.svg +0 -0
  46. {physlint-0.3.1 → physlint-0.3.2}/docs/design/mcap-ros.md +0 -0
  47. {physlint-0.3.1 → physlint-0.3.2}/docs/launch/README.md +0 -0
  48. {physlint-0.3.1 → physlint-0.3.2}/docs/launch/capture-assets.md +0 -0
  49. {physlint-0.3.1 → physlint-0.3.2}/docs/launch/post-templates.md +0 -0
  50. {physlint-0.3.1 → physlint-0.3.2}/docs/plugins.md +0 -0
  51. {physlint-0.3.1 → physlint-0.3.2}/docs/roadmap.md +0 -0
  52. {physlint-0.3.1 → physlint-0.3.2}/docs/rules/mcap-ros2-rules.md +0 -0
  53. {physlint-0.3.1 → physlint-0.3.2}/docs/rules/mvp-rules.md +0 -0
  54. {physlint-0.3.1 → physlint-0.3.2}/docs/validation/compatibility-survey.md +0 -0
  55. {physlint-0.3.1 → physlint-0.3.2}/docs/validation/mcap-ros2-2026-08-27.md +0 -0
  56. {physlint-0.3.1 → physlint-0.3.2}/docs/validation/real-data-2026-08-23.md +0 -0
  57. {physlint-0.3.1 → physlint-0.3.2}/examples/plugins/idle_prefix.py +0 -0
  58. {physlint-0.3.1 → physlint-0.3.2}/observatory/.gitignore +0 -0
  59. {physlint-0.3.1 → physlint-0.3.2}/observatory/.openai/hosting.json +0 -0
  60. {physlint-0.3.1 → physlint-0.3.2}/observatory/app/chatgpt-auth.ts +0 -0
  61. {physlint-0.3.1 → physlint-0.3.2}/observatory/app/layout.tsx +0 -0
  62. {physlint-0.3.1 → physlint-0.3.2}/observatory/data/comparisons.json +0 -0
  63. {physlint-0.3.1 → physlint-0.3.2}/observatory/db/index.ts +0 -0
  64. {physlint-0.3.1 → physlint-0.3.2}/observatory/db/schema.ts +0 -0
  65. {physlint-0.3.1 → physlint-0.3.2}/observatory/drizzle/meta/_journal.json +0 -0
  66. {physlint-0.3.1 → physlint-0.3.2}/observatory/drizzle.config.ts +0 -0
  67. {physlint-0.3.1 → physlint-0.3.2}/observatory/eslint.config.mjs +0 -0
  68. {physlint-0.3.1 → physlint-0.3.2}/observatory/examples/d1/app/api/notes/route.ts +0 -0
  69. {physlint-0.3.1 → physlint-0.3.2}/observatory/examples/d1/db/schema.ts +0 -0
  70. {physlint-0.3.1 → physlint-0.3.2}/observatory/next-env.d.ts +0 -0
  71. {physlint-0.3.1 → physlint-0.3.2}/observatory/next.config.ts +0 -0
  72. {physlint-0.3.1 → physlint-0.3.2}/observatory/package-lock.json +0 -0
  73. {physlint-0.3.1 → physlint-0.3.2}/observatory/package.json +0 -0
  74. {physlint-0.3.1 → physlint-0.3.2}/observatory/postcss.config.mjs +0 -0
  75. {physlint-0.3.1 → physlint-0.3.2}/observatory/public/favicon.png +0 -0
  76. {physlint-0.3.1 → physlint-0.3.2}/observatory/public/favicon.svg +0 -0
  77. {physlint-0.3.1 → physlint-0.3.2}/observatory/public/file.svg +0 -0
  78. {physlint-0.3.1 → physlint-0.3.2}/observatory/public/globe.svg +0 -0
  79. {physlint-0.3.1 → physlint-0.3.2}/observatory/public/physlint-observatory-social.png +0 -0
  80. {physlint-0.3.1 → physlint-0.3.2}/observatory/public/window.svg +0 -0
  81. {physlint-0.3.1 → physlint-0.3.2}/observatory/tsconfig.json +0 -0
  82. {physlint-0.3.1 → physlint-0.3.2}/observatory/vite.config.ts +0 -0
  83. {physlint-0.3.1 → physlint-0.3.2}/observatory/worker/index.ts +0 -0
  84. {physlint-0.3.1 → physlint-0.3.2}/src/physlint/__init__.py +0 -0
  85. {physlint-0.3.1 → physlint-0.3.2}/src/physlint/adapters/__init__.py +0 -0
  86. {physlint-0.3.1 → physlint-0.3.2}/src/physlint/adapters/base.py +0 -0
  87. {physlint-0.3.1 → physlint-0.3.2}/src/physlint/adapters/lerobot.py +0 -0
  88. {physlint-0.3.1 → physlint-0.3.2}/src/physlint/adapters/mcap.py +0 -0
  89. {physlint-0.3.1 → physlint-0.3.2}/src/physlint/api.py +0 -0
  90. {physlint-0.3.1 → physlint-0.3.2}/src/physlint/cli.py +0 -0
  91. {physlint-0.3.1 → physlint-0.3.2}/src/physlint/config.py +0 -0
  92. {physlint-0.3.1 → physlint-0.3.2}/src/physlint/corruptions.py +0 -0
  93. {physlint-0.3.1 → physlint-0.3.2}/src/physlint/engine/__init__.py +0 -0
  94. {physlint-0.3.1 → physlint-0.3.2}/src/physlint/engine/baseline.py +0 -0
  95. {physlint-0.3.1 → physlint-0.3.2}/src/physlint/engine/cache.py +0 -0
  96. {physlint-0.3.1 → physlint-0.3.2}/src/physlint/engine/compare.py +0 -0
  97. {physlint-0.3.1 → physlint-0.3.2}/src/physlint/engine/discovery.py +0 -0
  98. {physlint-0.3.1 → physlint-0.3.2}/src/physlint/engine/planner.py +0 -0
  99. {physlint-0.3.1 → physlint-0.3.2}/src/physlint/engine/runner.py +0 -0
  100. {physlint-0.3.1 → physlint-0.3.2}/src/physlint/models/__init__.py +0 -0
  101. {physlint-0.3.1 → physlint-0.3.2}/src/physlint/models/baseline.py +0 -0
  102. {physlint-0.3.1 → physlint-0.3.2}/src/physlint/models/comparison.py +0 -0
  103. {physlint-0.3.1 → physlint-0.3.2}/src/physlint/models/dataset.py +0 -0
  104. {physlint-0.3.1 → physlint-0.3.2}/src/physlint/models/finding.py +0 -0
  105. {physlint-0.3.1 → physlint-0.3.2}/src/physlint/models/mcap.py +0 -0
  106. {physlint-0.3.1 → physlint-0.3.2}/src/physlint/models/rule.py +0 -0
  107. {physlint-0.3.1 → physlint-0.3.2}/src/physlint/plugins.py +0 -0
  108. {physlint-0.3.1 → physlint-0.3.2}/src/physlint/py.typed +0 -0
  109. {physlint-0.3.1 → physlint-0.3.2}/src/physlint/reporters/__init__.py +0 -0
  110. {physlint-0.3.1 → physlint-0.3.2}/src/physlint/reporters/atomic.py +0 -0
  111. {physlint-0.3.1 → physlint-0.3.2}/src/physlint/reporters/html.py +0 -0
  112. {physlint-0.3.1 → physlint-0.3.2}/src/physlint/reporters/json.py +0 -0
  113. {physlint-0.3.1 → physlint-0.3.2}/src/physlint/reporters/junit.py +0 -0
  114. {physlint-0.3.1 → physlint-0.3.2}/src/physlint/reporters/sarif.py +0 -0
  115. {physlint-0.3.1 → physlint-0.3.2}/src/physlint/reporters/terminal.py +0 -0
  116. {physlint-0.3.1 → physlint-0.3.2}/src/physlint/rules/__init__.py +0 -0
  117. {physlint-0.3.1 → physlint-0.3.2}/src/physlint/rules/common.py +0 -0
  118. {physlint-0.3.1 → physlint-0.3.2}/src/physlint/rules/duplication.py +0 -0
  119. {physlint-0.3.1 → physlint-0.3.2}/src/physlint/rules/manifest.py +0 -0
  120. {physlint-0.3.1 → physlint-0.3.2}/src/physlint/rules/mcap.py +0 -0
  121. {physlint-0.3.1 → physlint-0.3.2}/src/physlint/rules/numeric.py +0 -0
  122. {physlint-0.3.1 → physlint-0.3.2}/src/physlint/rules/temporal.py +0 -0
  123. {physlint-0.3.1 → physlint-0.3.2}/src/physlint/rules/video.py +0 -0
  124. {physlint-0.3.1 → physlint-0.3.2}/tests/conftest.py +0 -0
  125. {physlint-0.3.1 → physlint-0.3.2}/tests/test_adapter.py +0 -0
  126. {physlint-0.3.1 → physlint-0.3.2}/tests/test_baseline.py +0 -0
  127. {physlint-0.3.1 → physlint-0.3.2}/tests/test_cache.py +0 -0
  128. {physlint-0.3.1 → physlint-0.3.2}/tests/test_compare.py +0 -0
  129. {physlint-0.3.1 → physlint-0.3.2}/tests/test_config.py +0 -0
  130. {physlint-0.3.1 → physlint-0.3.2}/tests/test_corruptions.py +0 -0
  131. {physlint-0.3.1 → physlint-0.3.2}/tests/test_mcap_adapter.py +0 -0
  132. {physlint-0.3.1 → physlint-0.3.2}/tests/test_mcap_rules.py +0 -0
  133. {physlint-0.3.1 → physlint-0.3.2}/tests/test_mcap_validation_harness.py +0 -0
  134. {physlint-0.3.1 → physlint-0.3.2}/tests/test_observatory_data.py +0 -0
  135. {physlint-0.3.1 → physlint-0.3.2}/tests/test_plugins.py +0 -0
  136. {physlint-0.3.1 → physlint-0.3.2}/tests/test_prepare_demo.py +0 -0
  137. {physlint-0.3.1 → physlint-0.3.2}/tests/test_release_metadata.py +0 -0
  138. {physlint-0.3.1 → physlint-0.3.2}/tests/test_reporters.py +0 -0
  139. {physlint-0.3.1 → physlint-0.3.2}/tests/test_rules.py +0 -0
  140. {physlint-0.3.1 → physlint-0.3.2}/tests/test_survey_harness.py +0 -0
  141. {physlint-0.3.1 → physlint-0.3.2}/tests/test_validation_harness.py +0 -0
  142. {physlint-0.3.1 → physlint-0.3.2}/validation/README.md +0 -0
  143. {physlint-0.3.1 → physlint-0.3.2}/validation/__init__.py +0 -0
  144. {physlint-0.3.1 → physlint-0.3.2}/validation/harness.py +0 -0
  145. {physlint-0.3.1 → physlint-0.3.2}/validation/mcap_harness.py +0 -0
  146. {physlint-0.3.1 → physlint-0.3.2}/validation/prepare_demo.py +0 -0
  147. {physlint-0.3.1 → physlint-0.3.2}/validation/render_assets.py +0 -0
  148. {physlint-0.3.1 → physlint-0.3.2}/validation/reports/lerobot-survey-2026-08-30/check-aloha-battery.json +0 -0
  149. {physlint-0.3.1 → physlint-0.3.2}/validation/reports/lerobot-survey-2026-08-30/check-lekiwi-go2.json +0 -0
  150. {physlint-0.3.1 → physlint-0.3.2}/validation/reports/lerobot-survey-2026-08-30/check-libero-spatial.json +0 -0
  151. {physlint-0.3.1 → physlint-0.3.2}/validation/reports/lerobot-survey-2026-08-30/check-pusht.json +0 -0
  152. {physlint-0.3.1 → physlint-0.3.2}/validation/reports/lerobot-survey-2026-08-30/check-reachy-head.json +0 -0
  153. {physlint-0.3.1 → physlint-0.3.2}/validation/reports/lerobot-survey-2026-08-30/check-so100-pickplace.json +0 -0
  154. {physlint-0.3.1 → physlint-0.3.2}/validation/reports/lerobot-survey-2026-08-30/check-so101-teleop.json +0 -0
  155. {physlint-0.3.1 → physlint-0.3.2}/validation/reports/lerobot-survey-2026-08-30/check-unitree-h1-greet.json +0 -0
  156. {physlint-0.3.1 → physlint-0.3.2}/validation/reports/lerobot-survey-2026-08-30/check-ur10e-robotiq.json +0 -0
  157. {physlint-0.3.1 → physlint-0.3.2}/validation/reports/lerobot-survey-2026-08-30/check-xarm-lift.json +0 -0
  158. {physlint-0.3.1 → physlint-0.3.2}/validation/reports/lerobot-survey-2026-08-30/summary.csv +0 -0
  159. {physlint-0.3.1 → physlint-0.3.2}/validation/reports/lerobot-survey-2026-08-30/summary.json +0 -0
  160. {physlint-0.3.1 → physlint-0.3.2}/validation/reports/lerobot-survey-2026-08-30/summary.sha256 +0 -0
  161. {physlint-0.3.1 → physlint-0.3.2}/validation/reports/mcap-ros2-2026-08-26/foxglove-ten-messages.json +0 -0
  162. {physlint-0.3.1 → physlint-0.3.2}/validation/reports/mcap-ros2-2026-08-26/robotis-arx5-button.json +0 -0
  163. {physlint-0.3.1 → physlint-0.3.2}/validation/reports/mcap-ros2-2026-08-26/ros2-joint-state-clean.json +0 -0
  164. {physlint-0.3.1 → physlint-0.3.2}/validation/reports/mcap-ros2-2026-08-26/ros2-joint-state-corrupt.json +0 -0
  165. {physlint-0.3.1 → physlint-0.3.2}/validation/reports/mcap-ros2-2026-08-26/summary.json +0 -0
  166. {physlint-0.3.1 → physlint-0.3.2}/validation/reports/real-data-2026-08-24/clean-panda.json +0 -0
  167. {physlint-0.3.1 → physlint-0.3.2}/validation/reports/real-data-2026-08-24/clean-rover.json +0 -0
  168. {physlint-0.3.1 → physlint-0.3.2}/validation/reports/real-data-2026-08-24/clean-sentinel.json +0 -0
  169. {physlint-0.3.1 → physlint-0.3.2}/validation/reports/real-data-2026-08-24/clean-so101.json +0 -0
  170. {physlint-0.3.1 → physlint-0.3.2}/validation/reports/real-data-2026-08-24/corruption-nan.json +0 -0
  171. {physlint-0.3.1 → physlint-0.3.2}/validation/reports/real-data-2026-08-24/corruption-reordered.json +0 -0
  172. {physlint-0.3.1 → physlint-0.3.2}/validation/reports/real-data-2026-08-24/corruption-truncated.json +0 -0
  173. {physlint-0.3.1 → physlint-0.3.2}/validation/reports/real-data-2026-08-24/summary.csv +0 -0
  174. {physlint-0.3.1 → physlint-0.3.2}/validation/reports/real-data-2026-08-24/summary.json +0 -0
  175. {physlint-0.3.1 → physlint-0.3.2}/validation/survey_harness.py +0 -0
@@ -0,0 +1,59 @@
1
+ name: Community evidence submission
2
+ description: Put a public robot dataset or recording on the Physlint Community Evidence Atlas.
3
+ title: "[evidence]: "
4
+ labels: ["evidence", "community"]
5
+ body:
6
+ - type: markdown
7
+ attributes:
8
+ value: |
9
+ Thanks for contributing to the public map of robot data health. Submit only public, non-sensitive sources that can be revision-pinned. Do not attach private datasets, credentials, or reports containing private paths.
10
+ - type: input
11
+ id: source
12
+ attributes:
13
+ label: Public dataset or recording
14
+ description: Link the public repository, dataset, or recording.
15
+ placeholder: https://huggingface.co/datasets/owner/dataset
16
+ validations:
17
+ required: true
18
+ - type: input
19
+ id: revision
20
+ attributes:
21
+ label: Immutable revision
22
+ description: Provide a commit, tag, release, checksum, or other stable revision when available.
23
+ placeholder: Commit SHA, tag, or release identifier
24
+ validations:
25
+ required: true
26
+ - type: dropdown
27
+ id: profile
28
+ attributes:
29
+ label: Data profile
30
+ options:
31
+ - LeRobot
32
+ - Generic MCAP
33
+ - ROS 2 over MCAP
34
+ - Another format
35
+ validations:
36
+ required: true
37
+ - type: textarea
38
+ id: context
39
+ attributes:
40
+ label: Robot and collection context
41
+ description: Tell the community what robot, task, sensors, and collection setup this evidence represents.
42
+ validations:
43
+ required: true
44
+ - type: textarea
45
+ id: expectation
46
+ attributes:
47
+ label: What should we learn from it?
48
+ description: Describe whether you expect a healthy result, a known defect, or a finding that needs review.
49
+ validations:
50
+ required: true
51
+ - type: checkboxes
52
+ id: consent
53
+ attributes:
54
+ label: Publication agreement
55
+ options:
56
+ - label: I confirm this source is public and may be referenced by name in the Community Evidence Atlas.
57
+ required: true
58
+ - label: I understand Physlint will publish scoped validation evidence, not a safety certification or universal quality score.
59
+ required: true
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.3.2 — 2026-09-06
4
+
5
+ - Launch the Physlint Community Evidence Atlas with 23 published observations, community survey context, real defect stories, and stable evidence links.
6
+ - Add a public evidence-submission workflow for dataset and recording maintainers.
7
+ - Replace the public regressions section with a clearer community narrative while retaining the generated comparison catalog for reproducibility.
8
+ - Refresh the PyPI monthly download snapshot to 289 downloads.
9
+
3
10
  ## 0.3.1 — 2026-08-30
4
11
 
5
12
  - Add a stratified LeRobot compatibility survey, kept separate from the four-snapshot release gate.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: physlint
3
- Version: 0.3.1
3
+ Version: 0.3.2
4
4
  Summary: Local-first integrity validation for physical-AI and robot-learning data
5
5
  Project-URL: Homepage, https://github.com/pranayjoshi/physlint
6
6
  Project-URL: Documentation, https://github.com/pranayjoshi/physlint#readme
@@ -54,17 +54,19 @@ Local-first, deterministic validation for physical-AI recordings and robot-learn
54
54
  [![Downloads per month](https://img.shields.io/endpoint?url=https%3A%2F%2Fraw.githubusercontent.com%2Fpranayjoshi%2Fphyslint%2Fmaster%2Fdocs%2Fmetrics%2Fdownloads.json&style=flat-square)](https://pypistats.org/packages/physlint)
55
55
  ![Python](https://img.shields.io/badge/Python-3.11%2B-3776AB?style=flat-square&logo=python&logoColor=white)
56
56
  [![MIT](https://img.shields.io/badge/License-MIT-2ea44f?style=flat-square)](LICENSE)
57
- ![Status](https://img.shields.io/badge/Status-Public%20Alpha-f59e0b?style=flat-square)
57
+ ![Status](https://img.shields.io/badge/Status-Released-0f766e?style=flat-square)
58
58
 
59
59
  [Quickstart](#quickstart) · [Demo](#see-it-catch-a-real-defect) · [Rules](#what-physlint-checks) · [Evidence](#reproducible-public-data-evidence) · [Observatory](#physlint-observatory) · [Roadmap](#format-roadmap) · [Contributing](#contributing)
60
60
 
61
- <img src="docs/assets/launch/exports/validation-summary.png" alt="Physlint public-alpha validation: four of four clean snapshots passed and three of three controlled corruptions were detected across 74 episodes and 31,258 frames." width="100%">
61
+ <img src="docs/assets/launch/exports/evidence-index.png" alt="Physlint evidence index showing robot dataset and recording health checks across LeRobot, MCAP, and ROS 2 data." width="100%">
62
62
 
63
63
  </div>
64
64
 
65
65
  Physlint finds concrete integrity defects before robot data reaches training. It explains the impact, identifies the affected episode and stream, recommends remediation, writes a stable JSON report, and returns a CI-safe exit code.
66
66
 
67
- The released `0.3.1` supports **LeRobot Dataset v3.x**, generic **MCAP** container validation, and a **ROS 2-over-MCAP** semantic profile, plus dataset comparison, reviewed baselines, CI report formats, and a plugin SDK. Claims stay scoped to pinned conformance data and controlled evidence. Native rosbag2 SQLite remains a conversion workflow.
67
+ The released `0.3.2` supports **LeRobot Dataset v3.x**, generic **MCAP** container validation, and a **ROS 2-over-MCAP** semantic profile, plus dataset comparison, reviewed baselines, CI report formats, and a plugin SDK. It also launches the [Community Evidence Atlas](https://physlint.com), where maintainers can explore reproducible findings and submit public robot data for inclusion. Claims stay scoped to pinned conformance data and controlled evidence. Native rosbag2 SQLite remains a conversion workflow.
68
+
69
+ At the `0.3.2` release snapshot, PyPI Stats reported **289 downloads in the preceding month**.
68
70
 
69
71
  > [!IMPORTANT]
70
72
  > Physlint validates configured data-integrity contracts. A pass does not certify policy quality, task success, or robot safety.
@@ -84,13 +86,13 @@ Physlint requires Python 3.11 or newer.
84
86
  ### Install from PyPI
85
87
 
86
88
  ```bash
87
- python -m pip install "physlint[video]==0.3.1"
89
+ python -m pip install "physlint[video]==0.3.2"
88
90
  ```
89
91
 
90
92
  To test the exact tagged source instead of the PyPI distribution, install the GitHub release directly:
91
93
 
92
94
  ```bash
93
- python -m pip install "physlint[video] @ git+https://github.com/pranayjoshi/physlint.git@v0.3.1"
95
+ python -m pip install "physlint[video] @ git+https://github.com/pranayjoshi/physlint.git@v0.3.2"
94
96
  ```
95
97
 
96
98
  ### Check a LeRobot dataset or MCAP recording
@@ -264,7 +266,7 @@ The CLI has stable exit codes and writes reports atomically, so a basic GitHub A
264
266
 
265
267
  ```yaml
266
268
  - name: Install Physlint
267
- run: python -m pip install "physlint[video]==0.3.1"
269
+ run: python -m pip install "physlint[video]==0.3.2"
268
270
 
269
271
  - name: Validate robot dataset
270
272
  run: |
@@ -328,7 +330,7 @@ See the [MCAP/ROS 2 manifest](validation/mcap_manifest.yaml), [reproduction harn
328
330
 
329
331
  ## Physlint Observatory
330
332
 
331
- The repository now includes the [Physlint Observatory](observatory/): a profile-aware public evidence index spanning LeRobot, MCAP, and ROS 2, plus fingerprint-level regression diffs from committed clean-versus-corruption reports. It deliberately does not collapse unlike contracts into one universal quality score. Every row exposes provenance, applicable checks, findings, and a report link.
333
+ The repository now includes the [Physlint Community Evidence Atlas](observatory/): a profile-aware public map spanning LeRobot, MCAP, and ROS 2, with real defect stories and a contribution path for dataset maintainers. It deliberately does not collapse unlike contracts into one universal quality score. Every row exposes provenance, applicable checks, findings, a stable share link, and a sanitized report.
332
334
 
333
335
  ## Format roadmap
334
336
 
@@ -442,7 +444,7 @@ Read [CONTRIBUTING.md](CONTRIBUTING.md), open a format request, or join [GitHub
442
444
 
443
445
  ## Project status
444
446
 
445
- Physlint is an alpha. Its claims are deliberately limited to the documented LeRobot, generic MCAP, and ROS 2-over-MCAP boundaries and their committed evidence. The project does not train policies, repair data, host datasets, infer task success, produce an opaque quality score, or certify that a robot or policy is safe.
447
+ Physlint is released. Its claims are deliberately limited to the documented LeRobot, generic MCAP, and ROS 2-over-MCAP boundaries and their committed evidence. The project does not train policies, repair data, host datasets, infer task success, produce an opaque quality score, or certify that a robot or policy is safe.
446
448
 
447
449
  See [CHANGELOG.md](CHANGELOG.md) for release notes.
448
450
 
@@ -11,17 +11,19 @@ Local-first, deterministic validation for physical-AI recordings and robot-learn
11
11
  [![Downloads per month](https://img.shields.io/endpoint?url=https%3A%2F%2Fraw.githubusercontent.com%2Fpranayjoshi%2Fphyslint%2Fmaster%2Fdocs%2Fmetrics%2Fdownloads.json&style=flat-square)](https://pypistats.org/packages/physlint)
12
12
  ![Python](https://img.shields.io/badge/Python-3.11%2B-3776AB?style=flat-square&logo=python&logoColor=white)
13
13
  [![MIT](https://img.shields.io/badge/License-MIT-2ea44f?style=flat-square)](LICENSE)
14
- ![Status](https://img.shields.io/badge/Status-Public%20Alpha-f59e0b?style=flat-square)
14
+ ![Status](https://img.shields.io/badge/Status-Released-0f766e?style=flat-square)
15
15
 
16
16
  [Quickstart](#quickstart) · [Demo](#see-it-catch-a-real-defect) · [Rules](#what-physlint-checks) · [Evidence](#reproducible-public-data-evidence) · [Observatory](#physlint-observatory) · [Roadmap](#format-roadmap) · [Contributing](#contributing)
17
17
 
18
- <img src="docs/assets/launch/exports/validation-summary.png" alt="Physlint public-alpha validation: four of four clean snapshots passed and three of three controlled corruptions were detected across 74 episodes and 31,258 frames." width="100%">
18
+ <img src="docs/assets/launch/exports/evidence-index.png" alt="Physlint evidence index showing robot dataset and recording health checks across LeRobot, MCAP, and ROS 2 data." width="100%">
19
19
 
20
20
  </div>
21
21
 
22
22
  Physlint finds concrete integrity defects before robot data reaches training. It explains the impact, identifies the affected episode and stream, recommends remediation, writes a stable JSON report, and returns a CI-safe exit code.
23
23
 
24
- The released `0.3.1` supports **LeRobot Dataset v3.x**, generic **MCAP** container validation, and a **ROS 2-over-MCAP** semantic profile, plus dataset comparison, reviewed baselines, CI report formats, and a plugin SDK. Claims stay scoped to pinned conformance data and controlled evidence. Native rosbag2 SQLite remains a conversion workflow.
24
+ The released `0.3.2` supports **LeRobot Dataset v3.x**, generic **MCAP** container validation, and a **ROS 2-over-MCAP** semantic profile, plus dataset comparison, reviewed baselines, CI report formats, and a plugin SDK. It also launches the [Community Evidence Atlas](https://physlint.com), where maintainers can explore reproducible findings and submit public robot data for inclusion. Claims stay scoped to pinned conformance data and controlled evidence. Native rosbag2 SQLite remains a conversion workflow.
25
+
26
+ At the `0.3.2` release snapshot, PyPI Stats reported **289 downloads in the preceding month**.
25
27
 
26
28
  > [!IMPORTANT]
27
29
  > Physlint validates configured data-integrity contracts. A pass does not certify policy quality, task success, or robot safety.
@@ -41,13 +43,13 @@ Physlint requires Python 3.11 or newer.
41
43
  ### Install from PyPI
42
44
 
43
45
  ```bash
44
- python -m pip install "physlint[video]==0.3.1"
46
+ python -m pip install "physlint[video]==0.3.2"
45
47
  ```
46
48
 
47
49
  To test the exact tagged source instead of the PyPI distribution, install the GitHub release directly:
48
50
 
49
51
  ```bash
50
- python -m pip install "physlint[video] @ git+https://github.com/pranayjoshi/physlint.git@v0.3.1"
52
+ python -m pip install "physlint[video] @ git+https://github.com/pranayjoshi/physlint.git@v0.3.2"
51
53
  ```
52
54
 
53
55
  ### Check a LeRobot dataset or MCAP recording
@@ -221,7 +223,7 @@ The CLI has stable exit codes and writes reports atomically, so a basic GitHub A
221
223
 
222
224
  ```yaml
223
225
  - name: Install Physlint
224
- run: python -m pip install "physlint[video]==0.3.1"
226
+ run: python -m pip install "physlint[video]==0.3.2"
225
227
 
226
228
  - name: Validate robot dataset
227
229
  run: |
@@ -285,7 +287,7 @@ See the [MCAP/ROS 2 manifest](validation/mcap_manifest.yaml), [reproduction harn
285
287
 
286
288
  ## Physlint Observatory
287
289
 
288
- The repository now includes the [Physlint Observatory](observatory/): a profile-aware public evidence index spanning LeRobot, MCAP, and ROS 2, plus fingerprint-level regression diffs from committed clean-versus-corruption reports. It deliberately does not collapse unlike contracts into one universal quality score. Every row exposes provenance, applicable checks, findings, and a report link.
290
+ The repository now includes the [Physlint Community Evidence Atlas](observatory/): a profile-aware public map spanning LeRobot, MCAP, and ROS 2, with real defect stories and a contribution path for dataset maintainers. It deliberately does not collapse unlike contracts into one universal quality score. Every row exposes provenance, applicable checks, findings, a stable share link, and a sanitized report.
289
291
 
290
292
  ## Format roadmap
291
293
 
@@ -399,7 +401,7 @@ Read [CONTRIBUTING.md](CONTRIBUTING.md), open a format request, or join [GitHub
399
401
 
400
402
  ## Project status
401
403
 
402
- Physlint is an alpha. Its claims are deliberately limited to the documented LeRobot, generic MCAP, and ROS 2-over-MCAP boundaries and their committed evidence. The project does not train policies, repair data, host datasets, infer task success, produce an opaque quality score, or certify that a robot or policy is safe.
404
+ Physlint is released. Its claims are deliberately limited to the documented LeRobot, generic MCAP, and ROS 2-over-MCAP boundaries and their committed evidence. The project does not train policies, repair data, host datasets, infer task success, produce an opaque quality score, or certify that a robot or policy is safe.
403
405
 
404
406
  See [CHANGELOG.md](CHANGELOG.md) for release notes.
405
407
 
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
3
  "label": "downloads/month",
4
- "message": "180",
4
+ "message": "289",
5
5
  "color": "brightgreen",
6
6
  "cacheSeconds": 86400,
7
- "updated_at": "2026-08-30T20:25:18.974471+00:00",
7
+ "updated_at": "2026-09-07T02:45:03.175664+00:00",
8
8
  "source": "https://pypistats.org/api/packages/physlint/recent?period=month"
9
9
  }
@@ -1,6 +1,6 @@
1
- # Physlint Observatory
1
+ # Physlint Community Evidence Atlas
2
2
 
3
- The public evidence index for Physlint. It presents revision-pinned LeRobot, MCAP, and ROS 2 validation results, plus fingerprint-level regression diffs, without collapsing unlike quality contracts into a universal score.
3
+ The public community evidence atlas for Physlint. It presents revision-pinned LeRobot, MCAP, and ROS 2 validation results, real defect stories, and a path for maintainers to contribute public datasets without collapsing unlike quality contracts into a universal score.
4
4
 
5
5
  Release-gate rows stay Public or Controlled. Compatibility-survey rows are tagged Survey and are not a Hugging Face quality score. See `docs/validation/compatibility-survey.md`.
6
6
 
@@ -12,7 +12,8 @@ export type Observation = {
12
12
  scale: string;
13
13
  checks: number;
14
14
  findings: number;
15
- status: "Passed" | "Issues found";
15
+ status: "Passed" | "Issues found" | "Rejected";
16
+ note?: string;
16
17
  reportUrl: string;
17
18
  sourceUrl?: string;
18
19
  revision?: string;
@@ -49,22 +50,22 @@ export function ObservatoryTable({ observations }: { observations: Observation[]
49
50
  <table>
50
51
  <thead><tr><th>#</th><th>Dataset / recording</th><th>Profile</th><th>Scale</th><th>Checks</th><th>Findings</th><th>Outcome</th><th>Evidence</th></tr></thead>
51
52
  <tbody>{filtered.map((item, index) => (
52
- <tr key={item.id}>
53
+ <tr id={`record-${item.id}`} key={item.id}>
53
54
  <td className="rank">{String(index + 1).padStart(2, "0")}</td>
54
55
  <td>
55
56
  {item.sourceUrl ? <a className="recording-name" href={item.sourceUrl}>{item.name} ↗</a> : <span className="recording-name">{item.name}</span>}
56
- <span className="recording-meta">{item.robot} · {item.provenance} evidence</span>
57
+ <span className="recording-meta">{item.robot} · {item.provenance} evidence{item.note ? ` · ${item.note}` : ""}</span>
57
58
  </td>
58
59
  <td><span className={`profile profile-${item.profile.toLowerCase().replace(" ", "-")}`}>{item.profile}</span></td>
59
60
  <td>{item.scale}</td><td>{item.checks}</td><td>{item.findings}</td>
60
- <td><span className={item.status === "Passed" ? "status pass" : "status issue"}>{item.status}</span></td>
61
- <td><a className="evidence" href={item.reportUrl} aria-label={`Open evidence for ${item.name}`}>Report ↗</a></td>
61
+ <td><span className={item.status === "Passed" ? "status pass" : item.status === "Rejected" ? "status reject" : "status issue"}>{item.status}</span></td>
62
+ <td><a className="evidence" href={item.reportUrl} aria-label={`Open evidence for ${item.name}`}>Report ↗</a><span className="evidence-separator"> · </span><a className="evidence" href={`#record-${item.id}`} aria-label={`Copyable link for ${item.name}`}>Link</a></td>
62
63
  </tr>
63
64
  ))}</tbody>
64
65
  </table>
65
66
  {filtered.length === 0 && <p className="empty">No observations match this filter.</p>}
66
67
  </div>
67
- <p className="index-note">Order shows the current evidence catalog—not a universal quality ranking. Different profiles run different contracts.</p>
68
+ <p className="index-note">Order is the catalog, not a ranking. Release-gate rows are the public claim. Survey rows are compatibility observations and may include classified false positives.</p>
68
69
  </>
69
70
  );
70
71
  }
@@ -62,10 +62,26 @@ tbody tr:hover { background:rgba(255,255,255,.45); }
62
62
  .profile-mcap { background:#dbe9e5; color:#075f53; }.profile-ros-2 { background:#e6edcb; color:#465a12; }
63
63
  .status { display:inline-flex; align-items:center; gap:7px; white-space:nowrap; font-weight:700; }
64
64
  .status::before { content:""; width:8px; height:8px; border-radius:50%; background:currentColor; }
65
- .pass { color:var(--teal); }.issue { color:var(--red); }
65
+ .pass { color:var(--teal); }.issue { color:var(--red); }.reject { color:#8a6a12; }
66
66
  .evidence { font:650 11px/1 var(--font-geist-mono); text-underline-offset:4px; }
67
67
  .empty { margin:0; padding:40px 10px; color:var(--muted); }
68
68
  .index-note { margin:14px 0 0; color:var(--muted); font-size:11px; }
69
+ .evidence-separator { color:var(--line); }
70
+ .findings { padding:70px 0 20px; }
71
+ .finding-grid { display:grid; grid-template-columns:repeat(3,1fr); border-top:2px solid var(--ink); border-left:1px solid var(--line); }
72
+ .finding-grid article { min-height:265px; padding:28px; border-right:1px solid var(--line); border-bottom:1px solid var(--line); background:rgba(255,255,255,.3); }
73
+ .finding-grid strong { display:block; margin-bottom:42px; color:var(--teal); font:650 48px/1 var(--font-geist-mono); letter-spacing:-.06em; }
74
+ .finding-grid h3 { max-width:240px; margin:0 0 12px; font-size:21px; letter-spacing:-.035em; }
75
+ .finding-grid p { margin:0; color:var(--muted); font-size:14px; line-height:1.55; }
76
+ .stories { padding:0 0 110px; }
77
+ .story-grid { display:grid; grid-template-columns:repeat(2,1fr); border-top:2px solid var(--ink); border-left:1px solid var(--line); }
78
+ .story-grid article { display:flex; min-height:340px; padding:28px; flex-direction:column; border-right:1px solid var(--line); border-bottom:1px solid var(--line); background:rgba(255,255,255,.34); }
79
+ .story-meta { display:flex; align-items:center; justify-content:space-between; color:var(--teal); font:700 10px/1 var(--font-geist-mono); letter-spacing:.09em; text-transform:uppercase; }
80
+ .story-grid h3 { max-width:460px; margin:52px 0 14px; font-size:28px; line-height:1.04; letter-spacing:-.045em; }
81
+ .story-grid>article>p { max-width:500px; margin:0; color:var(--muted); font-size:14px; line-height:1.6; }
82
+ .story-footer { display:flex; align-items:end; justify-content:space-between; gap:18px; margin-top:auto; padding-top:30px; }
83
+ .story-footer code { color:var(--teal); font-size:11px; }
84
+ .story-footer a { font:700 11px/1 var(--font-geist-mono); text-underline-offset:4px; }
69
85
  .method { padding:110px 0; background:var(--night); color:#f2f2e8; }
70
86
  .method>.shell { display:grid; grid-template-columns:.8fr 1.2fr; gap:90px; }
71
87
  .light { color:var(--acid); }
@@ -74,6 +90,15 @@ tbody tr:hover { background:rgba(255,255,255,.45); }
74
90
  .principles span { color:var(--acid); font:600 11px/1 var(--font-geist-mono); }
75
91
  .principles h3 { margin:35px 0 10px; font-size:22px; letter-spacing:-.03em; }
76
92
  .principles p { margin:0; color:#b1bdb9; font-size:14px; line-height:1.55; }
93
+ .contribute { display:grid; grid-template-columns:1fr 1fr; gap:80px; padding:110px 0; }
94
+ .contribute h2 { margin:0; font-size:clamp(42px,6vw,72px); line-height:.94; letter-spacing:-.06em; }
95
+ .contribute-copy>p:not(.eyebrow) { max-width:620px; margin:28px 0; color:var(--muted); font-size:17px; line-height:1.6; }
96
+ .contribute-copy .hero-actions { margin:0; }
97
+ .contribute-steps { margin:0; padding:0; list-style:none; border-top:2px solid var(--ink); }
98
+ .contribute-steps li { display:grid; grid-template-columns:55px 1fr; gap:18px; padding:25px 0; border-bottom:1px solid var(--line); }
99
+ .contribute-steps li>span { color:var(--teal); font:700 11px/1.4 var(--font-geist-mono); }
100
+ .contribute-steps h3 { margin:0 0 7px; font-size:18px; letter-spacing:-.025em; }
101
+ .contribute-steps p { margin:0; color:var(--muted); font-size:14px; line-height:1.5; }
77
102
  .cta { padding:115px 0; text-align:center; }
78
103
  .cta .eyebrow { text-align:center; }
79
104
  .cta>div { display:flex; justify-content:center; gap:10px; margin-top:35px; }
@@ -87,13 +112,13 @@ tbody tr:hover { background:rgba(255,255,255,.45); }
87
112
  .footer { display:flex; justify-content:space-between; gap:30px; padding:25px 0 35px; border-top:1px solid var(--line); color:var(--muted); font-size:11px; }
88
113
 
89
114
  @media (prefers-reduced-motion:reduce) { * { scroll-behavior:auto!important; transition:none!important; } }
90
- @media (max-width:900px) { .hero-orbit { opacity:.28; right:-170px; }.method>.shell { grid-template-columns:1fr; gap:55px; } }
115
+ @media (max-width:900px) { .hero-orbit { opacity:.28; right:-170px; }.method>.shell,.contribute { grid-template-columns:1fr; gap:55px; }.finding-grid { grid-template-columns:1fr; }.finding-grid article { min-height:auto; }.finding-grid strong { margin-bottom:24px; } }
91
116
  @media (max-width:720px) {
92
117
  .shell { width:min(100% - 24px,1180px); }.nav { height:68px; }.nav-links a:not(.github) { display:none; }.hero { padding-top:70px; }
93
118
  h1 { font-size:clamp(45px,14vw,70px); }.lede { font-size:17px; }.hero-actions { flex-direction:column; align-items:stretch; }
94
119
  .summary { grid-template-columns:1fr 1fr; }.summary div:nth-child(2) { border-right:0; }.summary div:nth-child(-n+2) { border-bottom:1px solid var(--line); }
95
120
  .section-heading { display:block; }.section-heading>p { margin-top:14px; }.toolbar { align-items:stretch; flex-direction:column; }.search { width:100%; }
96
- .method { padding:80px 0; }.principles { grid-template-columns:1fr; }.principles article { min-height:180px; }.cta { padding:85px 0; }.cta>div { flex-direction:column; }
121
+ .method { padding:80px 0; }.principles,.story-grid { grid-template-columns:1fr; }.principles article { min-height:180px; }.story-grid article { min-height:310px; }.contribute { padding:80px 0; }.cta { padding:85px 0; }.cta>div { flex-direction:column; }
97
122
  .workflow-grid { grid-template-columns:1fr; }
98
123
  .footer { flex-direction:column; }
99
124
  }
@@ -0,0 +1,168 @@
1
+ import type { Metadata } from "next";
2
+ import { ObservatoryTable, type Observation } from "./ObservatoryTable";
3
+ import catalog from "../data/observations.json";
4
+
5
+ export const metadata: Metadata = {
6
+ title: "Community Evidence Atlas — robot data health",
7
+ description: "A community map of reproducible health evidence for LeRobot, MCAP, and ROS 2 datasets and recordings.",
8
+ other: { "codex-preview": "development" },
9
+ };
10
+
11
+ const repo = "https://github.com/pranayjoshi/physlint";
12
+ const reportRoot = `${repo}/blob/master/validation/reports`;
13
+ const observations: Observation[] = catalog.observations.map((item) => ({
14
+ ...item,
15
+ profile: item.profile as Observation["profile"],
16
+ provenance: item.provenance as Observation["provenance"],
17
+ status: item.status as Observation["status"],
18
+ note: typeof item.note === "string" ? item.note : undefined,
19
+ sourceUrl: item.sourceUrl ?? undefined,
20
+ reportUrl: `${reportRoot}/${item.reportPath}`,
21
+ }));
22
+ const ruleRuns = observations.reduce((total, item) => total + item.checks, 0);
23
+ const rosMessages = observations.find((item) => item.id === "robotis-arx5-button")?.scale.split(" ")[0] ?? "7,047";
24
+ const surveyCount = observations.filter((item) => item.provenance === "Survey").length;
25
+ const profileCount = new Set(observations.map((item) => item.profile)).size;
26
+
27
+ const stories = [
28
+ {
29
+ number: "01",
30
+ label: "Confirmed public defect",
31
+ title: "Metadata pointed to shards that were never published.",
32
+ copy: "The Reachy 2 Head sample declared Parquet files that were absent from its public revision. The dataset could be discovered, but not reliably consumed.",
33
+ rule: "manifest.required_files",
34
+ href: `${reportRoot}/lerobot-survey-2026-08-30/check-reachy-head.json`,
35
+ },
36
+ {
37
+ number: "02",
38
+ label: "Controlled evidence",
39
+ title: "One reordered timestamp exposed three timing failures.",
40
+ copy: "A deterministic edit reproduced clock reversal, an unexpected sampling interval, and an excessive gap—without changing the original source.",
41
+ rule: "temporal.monotonic",
42
+ href: `${reportRoot}/real-data-2026-08-24/corruption-reordered.json`,
43
+ },
44
+ {
45
+ number: "03",
46
+ label: "Controlled evidence",
47
+ title: "A single non-finite value was isolated before training.",
48
+ copy: "One injected NaN in robot state was traced to its episode, sample, stream, and dimension with a concrete remediation path.",
49
+ rule: "numeric.finite_values",
50
+ href: `${reportRoot}/real-data-2026-08-24/corruption-nan.json`,
51
+ },
52
+ {
53
+ number: "04",
54
+ label: "ROS 2 evidence",
55
+ title: "A topic gap and malformed JointState were separated cleanly.",
56
+ copy: "The recording showed both a cadence break and a position/name dimension mismatch, each reported under the rule that owns it.",
57
+ rule: "ros2.semantic_consistency",
58
+ href: `${reportRoot}/mcap-ros2-2026-08-26/ros2-joint-state-corrupt.json`,
59
+ },
60
+ ];
61
+
62
+ export default function Home() {
63
+ return (
64
+ <main>
65
+ <nav className="nav shell">
66
+ <a className="brand" href="#top" aria-label="Physlint Community Evidence Atlas home"><span className="brand-mark">P/</span><span>Evidence Atlas <small>by Physlint</small></span></a>
67
+ <div className="nav-links"><a href="#index">Atlas</a><a href="#stories">Findings</a><a href="#contribute">Contribute</a><a href="#method">Method</a><a className="github" href={repo}>GitHub ↗</a></div>
68
+ </nav>
69
+
70
+ <section className="hero shell" id="top">
71
+ <div className="hero-copy">
72
+ <p className="eyebrow">Community release · 06 Sep 2026</p>
73
+ <h1>The public map of<br />robot data health.</h1>
74
+ <p className="lede">An open atlas of robotics datasets, recordings, and the integrity evidence behind them. See what was checked, what needs review, and how to add your own data—without a mystery score.</p>
75
+ <div className="hero-actions"><a className="button primary" href="#index">Explore the atlas ↓</a><a className="button secondary" href="#contribute">Put your data on the map ↗</a></div>
76
+ </div>
77
+ <div className="hero-orbit" aria-hidden="true"><span className="orbit orbit-one"/><span className="orbit orbit-two"/><span className="core">P/</span><span className="signal signal-a"/><span className="signal signal-b"/><span className="signal signal-c"/></div>
78
+ <div className="summary" aria-label="Validation summary">
79
+ <div><strong>{observations.length}</strong><span>published observations</span></div>
80
+ <div><strong>{surveyCount}</strong><span>community survey records</span></div>
81
+ <div><strong>{ruleRuns.toLocaleString("en-US")}</strong><span>applicable checks</span></div>
82
+ <div><strong>{profileCount}</strong><span>quality profiles</span></div>
83
+ </div>
84
+ </section>
85
+
86
+ <section className="findings shell" aria-labelledby="findings-title">
87
+ <div className="section-heading">
88
+ <div><p className="eyebrow">What the evidence says today</p><h2 id="findings-title">A snapshot, not a verdict.</h2></div>
89
+ <p>The atlas separates release-gate evidence, community survey observations, and controlled defects so each result stays honest about what it proves.</p>
90
+ </div>
91
+ <div className="finding-grid">
92
+ <article><strong>6</strong><h3>Public sources checked</h3><p>Five healthy datasets or recordings passed their applicable contracts. One MCAP conformance case reproduced its known timestamp defects.</p></article>
93
+ <article><strong>15</strong><h3>Survey snapshots mapped</h3><p>Ten LeRobot v3 datasets were checked in depth. Five older v2 or v2.1 datasets were deliberately rejected rather than guessed through.</p></article>
94
+ <article><strong>{Number(rosMessages).toLocaleString("en-US")}</strong><h3>Real ROS messages decoded</h3><p>A public ARX X5 episode passed its configured ROS 2 contract, showing the atlas extends beyond training-dataset folders.</p></article>
95
+ </div>
96
+ </section>
97
+
98
+ <section className="index shell" id="index" aria-labelledby="index-title">
99
+ <div className="section-heading">
100
+ <div><p className="eyebrow">Community evidence atlas</p><h2 id="index-title">Explore every observation.</h2></div>
101
+ <p>Release-gate rows (Public or Controlled) are the scoped claim. Survey rows are a stratified Hub sample, including classified false positives and fail-closed v2 screens. “Passed” means the applicable checks found no configured blocking issues.</p>
102
+ </div>
103
+ <ObservatoryTable observations={observations} />
104
+ </section>
105
+
106
+ <section className="stories shell" id="stories" aria-labelledby="stories-title">
107
+ <div className="section-heading">
108
+ <div><p className="eyebrow">Evidence, made tangible</p><h2 id="stories-title">What a real defect looks like.</h2></div>
109
+ <p>Each story links to a sanitized report with the exact rule, evidence, impact, and suggested remediation.</p>
110
+ </div>
111
+ <div className="story-grid">
112
+ {stories.map((story) => (
113
+ <article key={story.number}>
114
+ <div className="story-meta"><span>{story.number}</span><span>{story.label}</span></div>
115
+ <h3>{story.title}</h3>
116
+ <p>{story.copy}</p>
117
+ <div className="story-footer"><code>{story.rule}</code><a href={story.href}>Read evidence ↗</a></div>
118
+ </article>
119
+ ))}
120
+ </div>
121
+ </section>
122
+
123
+ <section className="workflows shell" id="workflows" aria-labelledby="workflow-title">
124
+ <div className="section-heading">
125
+ <div><p className="eyebrow">Data-engineer workflow</p><h2 id="workflow-title">A quality contract that can live in CI.</h2></div>
126
+ </div>
127
+ <div className="workflow-grid">
128
+ <article><h3>compare</h3><p>Diff two dataset versions or JSON reports. Exit 1 only on new blocking findings.</p><code>physlint compare before/ after/</code></article>
129
+ <article><h3>baseline</h3><p>Accept a known fingerprint with author, reason, and optional expiry. New instances of the same rule still fail.</p><code>physlint baseline . --author ada --reason known</code></article>
130
+ <article><h3>CI reports</h3><p>JSON plus JUnit, SARIF, and a local HTML file. No images or raw samples are embedded.</p><code>--junit-output --sarif-output --html-output</code></article>
131
+ <article><h3>plugins</h3><p>Load a file or entry-point rule. Task-specific idle detection stays out of the default contract.</p><code>plugins: [idle_prefix.py:IdlePrefixRule]</code></article>
132
+ </div>
133
+ </section>
134
+
135
+ <section className="method" id="method">
136
+ <div className="shell">
137
+ <div className="method-title"><p className="eyebrow light">How to read the index</p><h2>Evidence over<br />leaderboard theater.</h2></div>
138
+ <div className="principles">
139
+ <article><span>01</span><h3>Profile-aware</h3><p>LeRobot, generic MCAP, and ROS 2 use separate contracts. Survey rows never collapse into the release-gate claim or a Hub quality score.</p></article>
140
+ <article><span>02</span><h3>Reproducible</h3><p>Sources are revision-pinned. Reports preserve configuration digests, rule versions, and SHA-256 fingerprints.</p></article>
141
+ <article><span>03</span><h3>Privacy-safe</h3><p>Only sanitized evidence is published. Raw robot recordings, images, and full samples stay with their owners.</p></article>
142
+ <article><span>04</span><h3>Open to challenge</h3><p>Every finding identifies its rule and evidence. Disagree? Re-run it, inspect the report, or improve the rule.</p></article>
143
+ </div>
144
+ </div>
145
+ </section>
146
+
147
+ <section className="contribute shell" id="contribute" aria-labelledby="contribute-title">
148
+ <div className="contribute-copy">
149
+ <p className="eyebrow">Open call for evidence</p>
150
+ <h2 id="contribute-title">Put your robot data<br />on the map.</h2>
151
+ <p>Share an immutable public dataset or recording and what you expect it to demonstrate. Physlint will keep the source untouched, publish only sanitized evidence, and distinguish confirmed defects from findings that need human review.</p>
152
+ <div className="hero-actions"><a className="button primary" href={`${repo}/issues/new?template=evidence-submission.yml`}>Submit public evidence ↗</a><a className="button secondary" href={`${repo}/discussions`}>Join the discussion ↗</a></div>
153
+ </div>
154
+ <ol className="contribute-steps">
155
+ <li><span>01</span><div><h3>Share a public revision</h3><p>Link a dataset or recording that can be pinned and reproduced.</p></div></li>
156
+ <li><span>02</span><div><h3>Tell us what matters</h3><p>Describe the robot, format, and any real failure mode the community should understand.</p></div></li>
157
+ <li><span>03</span><div><h3>Get transparent evidence</h3><p>A published result names the checks, scope, provenance, and review status—never a universal score.</p></div></li>
158
+ </ol>
159
+ </section>
160
+
161
+ <section className="cta shell">
162
+ <p className="eyebrow">The atlas is open</p><h2>Make robot data quality<br />a shared public practice.</h2>
163
+ <div><code>pip install physlint</code><a className="button primary" href={`${repo}#quickstart`}>Run Physlint ↗</a></div>
164
+ </section>
165
+ <footer className="footer shell"><span>Physlint Community Evidence Atlas · Open source under MIT</span><span>Reports are scoped evidence, not safety certification.</span></footer>
166
+ </main>
167
+ );
168
+ }