asecli 0.8.2__tar.gz → 0.8.4__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 (262) hide show
  1. {asecli-0.8.2 → asecli-0.8.4}/.github/workflows/ci.yml +2 -11
  2. {asecli-0.8.2 → asecli-0.8.4}/.github/workflows/publish.yml +3 -12
  3. {asecli-0.8.2 → asecli-0.8.4}/AGENTS.md +7 -0
  4. {asecli-0.8.2 → asecli-0.8.4}/PKG-INFO +8 -8
  5. {asecli-0.8.2 → asecli-0.8.4}/README.md +7 -7
  6. asecli-0.8.4/docs/adversarial-audits/2026-09-14-132814-audit-report.md +94 -0
  7. asecli-0.8.4/docs/adversarial-audits/2026-09-14-132814-optimization-plan.md +56 -0
  8. {asecli-0.8.2 → asecli-0.8.4}/pyproject.toml +1 -1
  9. {asecli-0.8.2 → asecli-0.8.4}/skills/asecli/SKILL.md +13 -0
  10. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/__init__.py +1 -1
  11. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/cli/export_sg_command.py +34 -5
  12. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/contracts.py +3 -0
  13. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/sg_export/conversion_report.py +3 -0
  14. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/sg_export/decoder.py +2 -2
  15. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/sg_export/evidence.py +45 -5
  16. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/sg_export/model.py +2 -1
  17. asecli-0.8.4/src/asecli/sg_export/report_presentation.py +21 -0
  18. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/sg_export/report_semantics.py +5 -2
  19. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/sg_export/surface_matching.py +1 -35
  20. asecli-0.8.4/src/asecli/sg_export/surface_precision.py +66 -0
  21. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/sg_export/surface_semantics.py +20 -22
  22. asecli-0.8.4/tests/test_cross_cli_workflow.py +39 -0
  23. asecli-0.8.4/tests/test_export_precision_diagnostics.py +122 -0
  24. {asecli-0.8.2 → asecli-0.8.4}/tests/test_export_sg.py +7 -8
  25. {asecli-0.8.2 → asecli-0.8.4}/tests/test_governance.py +1 -1
  26. asecli-0.8.4/tests/test_smoke.py +4 -0
  27. {asecli-0.8.2 → asecli-0.8.4}/tests/test_surface_semantics.py +14 -11
  28. {asecli-0.8.2 → asecli-0.8.4}/tests/test_surface_semantics_integration.py +2 -0
  29. {asecli-0.8.2 → asecli-0.8.4}/tools/check_ci_governance.py +1 -0
  30. asecli-0.8.4/tools/independent_wheel_smoke.py +90 -0
  31. {asecli-0.8.2 → asecli-0.8.4}/uv.lock +2 -2
  32. asecli-0.8.2/.github/workflows/cross-cli.yml +0 -123
  33. asecli-0.8.2/tests/test_cross_cli_workflow.py +0 -38
  34. asecli-0.8.2/tests/test_smoke.py +0 -4
  35. {asecli-0.8.2 → asecli-0.8.4}/.gitignore +0 -0
  36. {asecli-0.8.2 → asecli-0.8.4}/.project-architect.json +0 -0
  37. {asecli-0.8.2 → asecli-0.8.4}/LICENSE +0 -0
  38. {asecli-0.8.2 → asecli-0.8.4}/SECURITY.md +0 -0
  39. {asecli-0.8.2 → asecli-0.8.4}/docs/00-governance/audit-supplement.json +0 -0
  40. {asecli-0.8.2 → asecli-0.8.4}/docs/00-governance/change-register.md +0 -0
  41. {asecli-0.8.2 → asecli-0.8.4}/docs/00-governance/delivery-protocol.md +0 -0
  42. {asecli-0.8.2 → asecli-0.8.4}/docs/00-governance/project-charter.md +0 -0
  43. {asecli-0.8.2 → asecli-0.8.4}/docs/00-governance/supply-chain-policy.md +0 -0
  44. {asecli-0.8.2 → asecli-0.8.4}/docs/00-governance/timeline.md +0 -0
  45. {asecli-0.8.2 → asecli-0.8.4}/docs/00-governance/traceability.csv +0 -0
  46. {asecli-0.8.2 → asecli-0.8.4}/docs/01-architecture/assumption-experiments.md +0 -0
  47. {asecli-0.8.2 → asecli-0.8.4}/docs/01-architecture/module-map.md +0 -0
  48. {asecli-0.8.2 → asecli-0.8.4}/docs/01-architecture/project-architecture-and-requirements.md +0 -0
  49. {asecli-0.8.2 → asecli-0.8.4}/docs/01-architecture/technical-route.md +0 -0
  50. {asecli-0.8.2 → asecli-0.8.4}/docs/03-quality/bug-register.md +0 -0
  51. {asecli-0.8.2 → asecli-0.8.4}/docs/03-quality/regression-catalog.md +0 -0
  52. {asecli-0.8.2 → asecli-0.8.4}/docs/03-quality/test-strategy.md +0 -0
  53. {asecli-0.8.2 → asecli-0.8.4}/docs/04-delivery/project-plan-task-charter.md +0 -0
  54. {asecli-0.8.2 → asecli-0.8.4}/docs/04-delivery/roadmap.md +0 -0
  55. {asecli-0.8.2 → asecli-0.8.4}/docs/adversarial-audits/2026-09-01-014104-audit-report.md +0 -0
  56. {asecli-0.8.2 → asecli-0.8.4}/docs/adversarial-audits/2026-09-01-014104-optimization-plan.md +0 -0
  57. {asecli-0.8.2 → asecli-0.8.4}/docs/adversarial-audits/2026-09-01-145343-audit-report.md +0 -0
  58. {asecli-0.8.2 → asecli-0.8.4}/docs/adversarial-audits/2026-09-01-145343-optimization-plan.md +0 -0
  59. {asecli-0.8.2 → asecli-0.8.4}/docs/adversarial-audits/2026-09-01-193521-audit-report.md +0 -0
  60. {asecli-0.8.2 → asecli-0.8.4}/docs/adversarial-audits/2026-09-01-193521-optimization-plan.md +0 -0
  61. {asecli-0.8.2 → asecli-0.8.4}/docs/adversarial-audits/2026-09-01-203438-audit-report.md +0 -0
  62. {asecli-0.8.2 → asecli-0.8.4}/docs/adversarial-audits/2026-09-01-203438-optimization-plan.md +0 -0
  63. {asecli-0.8.2 → asecli-0.8.4}/docs/adversarial-audits/2026-09-02-121155-audit-report.md +0 -0
  64. {asecli-0.8.2 → asecli-0.8.4}/docs/adversarial-audits/2026-09-02-121155-optimization-plan.md +0 -0
  65. {asecli-0.8.2 → asecli-0.8.4}/docs/adversarial-audits/2026-09-02-175509-audit-report.md +0 -0
  66. {asecli-0.8.2 → asecli-0.8.4}/docs/adversarial-audits/2026-09-02-175509-optimization-plan.md +0 -0
  67. {asecli-0.8.2 → asecli-0.8.4}/docs/adversarial-audits/2026-09-04-122304-audit-report.md +0 -0
  68. {asecli-0.8.2 → asecli-0.8.4}/docs/adversarial-audits/2026-09-04-122304-optimization-plan.md +0 -0
  69. {asecli-0.8.2 → asecli-0.8.4}/docs/adversarial-audits/2026-09-05-142617-audit-report.md +0 -0
  70. {asecli-0.8.2 → asecli-0.8.4}/docs/adversarial-audits/2026-09-05-142617-optimization-plan.md +0 -0
  71. {asecli-0.8.2 → asecli-0.8.4}/docs/adversarial-audits/2026-09-05-160945-audit-report.md +0 -0
  72. {asecli-0.8.2 → asecli-0.8.4}/docs/adversarial-audits/2026-09-05-160945-optimization-plan.md +0 -0
  73. {asecli-0.8.2 → asecli-0.8.4}/docs/adversarial-audits/2026-09-05-213523-audit-report.md +0 -0
  74. {asecli-0.8.2 → asecli-0.8.4}/docs/adversarial-audits/2026-09-05-213523-optimization-plan.md +0 -0
  75. {asecli-0.8.2 → asecli-0.8.4}/docs/adversarial-audits/2026-09-10-193631-audit-report.md +0 -0
  76. {asecli-0.8.2 → asecli-0.8.4}/docs/adversarial-audits/2026-09-10-193631-optimization-plan.md +0 -0
  77. {asecli-0.8.2 → asecli-0.8.4}/docs/adversarial-audits/2026-09-14-123640-audit-report.md +0 -0
  78. {asecli-0.8.2 → asecli-0.8.4}/docs/adversarial-audits/2026-09-14-123640-optimization-plan.md +0 -0
  79. {asecli-0.8.2 → asecli-0.8.4}/docs/adversarial-audits/2026-09-14-124947-audit-report.md +0 -0
  80. {asecli-0.8.2 → asecli-0.8.4}/docs/adversarial-audits/2026-09-14-124947-optimization-plan.md +0 -0
  81. {asecli-0.8.2 → asecli-0.8.4}/docs/first-principles/2026-08-31-231401-optimization-plan.md +0 -0
  82. {asecli-0.8.2 → asecli-0.8.4}/docs/first-principles/2026-09-01-190656-optimization-plan.md +0 -0
  83. {asecli-0.8.2 → asecli-0.8.4}/docs/proposals/2026-09-07-shadergraph-to-ase-requirements.md +0 -0
  84. {asecli-0.8.2 → asecli-0.8.4}/scripts/install.ps1 +0 -0
  85. {asecli-0.8.2 → asecli-0.8.4}/scripts/install.sh +0 -0
  86. {asecli-0.8.2 → asecli-0.8.4}/skills/asecli/references/conversion-publication-receipt.v1.schema.json +0 -0
  87. {asecli-0.8.2 → asecli-0.8.4}/skills/asecli/references/conversion-workflow.md +0 -0
  88. {asecli-0.8.2 → asecli-0.8.4}/skills/asecli/references/layout-standard.md +0 -0
  89. {asecli-0.8.2 → asecli-0.8.4}/skills/asecli/references/master-output-settings-standard.md +0 -0
  90. {asecli-0.8.2 → asecli-0.8.4}/skills/asecli/references/material-property-standard.md +0 -0
  91. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/bridge/__init__.py +0 -0
  92. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/bridge/_editor_port_contract.py +0 -0
  93. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/bridge/_editor_primitives.py +0 -0
  94. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/bridge/_editor_spec_grammar.py +0 -0
  95. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/bridge/_editor_spec_io.py +0 -0
  96. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/bridge/_editor_spec_validation.py +0 -0
  97. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/bridge/_gui_handoff_store.py +0 -0
  98. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/bridge/_gui_project.py +0 -0
  99. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/bridge/_gui_resource_store.py +0 -0
  100. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/bridge/_gui_resource_upgrade.py +0 -0
  101. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/bridge/editor_create.py +0 -0
  102. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/bridge/editor_spec.py +0 -0
  103. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/bridge/graph_geometry.py +0 -0
  104. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/bridge/graph_geometry_parser.py +0 -0
  105. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/bridge/graph_inspect.py +0 -0
  106. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/bridge/gui_handoff.py +0 -0
  107. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/bridge/gui_presentation.py +0 -0
  108. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/bridge/gui_provider_detection.py +0 -0
  109. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/bridge/gui_runtime_probe.py +0 -0
  110. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/bridge/gui_support.py +0 -0
  111. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/bridge/gui_support_resource.py +0 -0
  112. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/bridge/mcp_client.py +0 -0
  113. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/bridge/recompile.py +0 -0
  114. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/bridge/render_settings.py +0 -0
  115. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/bridge/resource_text.py +0 -0
  116. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/bridge/resources/asecli_material_gui.authoring.part00.cs.txt +0 -0
  117. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/bridge/resources/asecli_material_gui.authoring.part01.cs.txt +0 -0
  118. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/bridge/resources/asecli_material_gui.authoring.store.cs.txt +0 -0
  119. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/bridge/resources/asecli_material_gui.condition.cs.txt +0 -0
  120. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/bridge/resources/asecli_material_gui.hydration.cs.txt +0 -0
  121. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/bridge/resources/asecli_material_gui.part00.cs.txt +0 -0
  122. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/bridge/resources/asecli_material_gui.part01.cs.txt +0 -0
  123. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/bridge/resources/asecli_material_gui.reconciliation.cs.txt +0 -0
  124. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/bridge/resources/asecli_material_gui.transaction.cs.txt +0 -0
  125. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/bridge/resources/editor_create.part00.cs.txt +0 -0
  126. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/bridge/resources/editor_create.part01.cs.txt +0 -0
  127. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/bridge/resources/editor_create.part02.cs.txt +0 -0
  128. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/bridge/resources/editor_create.part03.cs.txt +0 -0
  129. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/bridge/resources/editor_create.part04.cs.txt +0 -0
  130. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/bridge/resources/wire_route.transaction.cs.txt +0 -0
  131. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/bridge/wire_route.py +0 -0
  132. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/checks/__init__.py +0 -0
  133. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/checks/checksum.py +0 -0
  134. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/checks/local_vars.py +0 -0
  135. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/checks/usage.py +0 -0
  136. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/checks/validate.py +0 -0
  137. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/cli/__init__.py +0 -0
  138. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/cli/commands.py +0 -0
  139. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/cli/commentary_command.py +0 -0
  140. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/cli/contract.py +0 -0
  141. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/cli/contract_command.py +0 -0
  142. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/cli/conversion_output.py +0 -0
  143. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/cli/create_command.py +0 -0
  144. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/cli/custom_gui_command.py +0 -0
  145. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/cli/graph_review_command.py +0 -0
  146. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/cli/gui_provider.py +0 -0
  147. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/cli/gui_support_command.py +0 -0
  148. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/cli/io.py +0 -0
  149. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/cli/layout_command.py +0 -0
  150. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/cli/main.py +0 -0
  151. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/cli/migrate_package_command.py +0 -0
  152. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/cli/recompile_metadata.py +0 -0
  153. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/cli/skill_command.py +0 -0
  154. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/cli/usage_command.py +0 -0
  155. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/contracts/editor-graph-spec.v3.schema.json +0 -0
  156. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/contracts/sgcli.native.v3.schema.json +0 -0
  157. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/core/__init__.py +0 -0
  158. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/core/comment_bounds.py +0 -0
  159. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/core/comment_layout.py +0 -0
  160. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/core/comment_metrics.py +0 -0
  161. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/core/comment_purpose.py +0 -0
  162. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/core/commentary.py +0 -0
  163. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/core/compiled_metadata.py +0 -0
  164. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/core/compiled_properties.py +0 -0
  165. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/core/custom_gui.py +0 -0
  166. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/core/custom_gui_versions.py +0 -0
  167. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/core/fishbone_placement.py +0 -0
  168. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/core/fishbone_topology.py +0 -0
  169. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/core/graph_ops.py +0 -0
  170. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/core/graph_review.py +0 -0
  171. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/core/island_layout.py +0 -0
  172. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/core/layout.py +0 -0
  173. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/core/layout_audit.py +0 -0
  174. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/core/layout_audit_geometry.py +0 -0
  175. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/core/layout_audit_repeated.py +0 -0
  176. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/core/layout_graph.py +0 -0
  177. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/core/local_vars.py +0 -0
  178. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/core/material_gui_condition.py +0 -0
  179. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/core/material_gui_protocol.py +0 -0
  180. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/core/material_gui_spec.py +0 -0
  181. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/core/meticulous_layout.py +0 -0
  182. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/core/model.py +0 -0
  183. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/core/property_presentation.py +0 -0
  184. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/core/reuse_plan.py +0 -0
  185. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/core/wire_geometry.py +0 -0
  186. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/core/wire_router.py +0 -0
  187. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/export_sg.py +0 -0
  188. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/schema/__init__.py +0 -0
  189. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/schema/data/observed.json +0 -0
  190. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/schema/data/schemas.json +0 -0
  191. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/schema_validation.py +0 -0
  192. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/sg_export/__init__.py +0 -0
  193. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/sg_export/alpha_modulate.py +0 -0
  194. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/sg_export/binding.py +0 -0
  195. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/sg_export/custom_expression.py +0 -0
  196. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/sg_export/nodes.py +0 -0
  197. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/sg_export/pass_blend.py +0 -0
  198. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/sg_export/reconciliation.py +0 -0
  199. {asecli-0.8.2 → asecli-0.8.4}/src/asecli/sg_export/sources.py +0 -0
  200. {asecli-0.8.2 → asecli-0.8.4}/tests/TEST.md +0 -0
  201. {asecli-0.8.2 → asecli-0.8.4}/tests/__init__.py +0 -0
  202. {asecli-0.8.2 → asecli-0.8.4}/tests/conftest.py +0 -0
  203. {asecli-0.8.2 → asecli-0.8.4}/tests/editor_create_v3_fixture.py +0 -0
  204. {asecli-0.8.2 → asecli-0.8.4}/tests/fixtures/HLIT.shader +0 -0
  205. {asecli-0.8.2 → asecli-0.8.4}/tests/fixtures/asecli_material_gui_v0_2_0.cs.txt +0 -0
  206. {asecli-0.8.2 → asecli-0.8.4}/tests/fixtures/step-antialiasing.function.txt +0 -0
  207. {asecli-0.8.2 → asecli-0.8.4}/tests/test_adversarial_hardening.py +0 -0
  208. {asecli-0.8.2 → asecli-0.8.4}/tests/test_audit_fixes.py +0 -0
  209. {asecli-0.8.2 → asecli-0.8.4}/tests/test_bridge_contract.py +0 -0
  210. {asecli-0.8.2 → asecli-0.8.4}/tests/test_bridge_recompile.py +0 -0
  211. {asecli-0.8.2 → asecli-0.8.4}/tests/test_build_reproducibility.py +0 -0
  212. {asecli-0.8.2 → asecli-0.8.4}/tests/test_cli_contract.py +0 -0
  213. {asecli-0.8.2 → asecli-0.8.4}/tests/test_commentary.py +0 -0
  214. {asecli-0.8.2 → asecli-0.8.4}/tests/test_contract_schema.py +0 -0
  215. {asecli-0.8.2 → asecli-0.8.4}/tests/test_conversion_report_semantics.py +0 -0
  216. {asecli-0.8.2 → asecli-0.8.4}/tests/test_core_contract.py +0 -0
  217. {asecli-0.8.2 → asecli-0.8.4}/tests/test_create.py +0 -0
  218. {asecli-0.8.2 → asecli-0.8.4}/tests/test_create_constant_presentation.py +0 -0
  219. {asecli-0.8.2 → asecli-0.8.4}/tests/test_custom_gui.py +0 -0
  220. {asecli-0.8.2 → asecli-0.8.4}/tests/test_custom_gui_cli.py +0 -0
  221. {asecli-0.8.2 → asecli-0.8.4}/tests/test_editor_create_bridge.py +0 -0
  222. {asecli-0.8.2 → asecli-0.8.4}/tests/test_editor_create_cli.py +0 -0
  223. {asecli-0.8.2 → asecli-0.8.4}/tests/test_editor_create_e2e.py +0 -0
  224. {asecli-0.8.2 → asecli-0.8.4}/tests/test_editor_create_spec.py +0 -0
  225. {asecli-0.8.2 → asecli-0.8.4}/tests/test_editor_create_spec_v3.py +0 -0
  226. {asecli-0.8.2 → asecli-0.8.4}/tests/test_editor_render_settings.py +0 -0
  227. {asecli-0.8.2 → asecli-0.8.4}/tests/test_export_property_visibility.py +0 -0
  228. {asecli-0.8.2 → asecli-0.8.4}/tests/test_graph_review.py +0 -0
  229. {asecli-0.8.2 → asecli-0.8.4}/tests/test_graph_safety.py +0 -0
  230. {asecli-0.8.2 → asecli-0.8.4}/tests/test_gui_handoff.py +0 -0
  231. {asecli-0.8.2 → asecli-0.8.4}/tests/test_gui_native_extension.py +0 -0
  232. {asecli-0.8.2 → asecli-0.8.4}/tests/test_gui_support.py +0 -0
  233. {asecli-0.8.2 → asecli-0.8.4}/tests/test_gui_support_cli_contract.py +0 -0
  234. {asecli-0.8.2 → asecli-0.8.4}/tests/test_gui_upgrade.py +0 -0
  235. {asecli-0.8.2 → asecli-0.8.4}/tests/test_install_scripts.py +0 -0
  236. {asecli-0.8.2 → asecli-0.8.4}/tests/test_island_layout.py +0 -0
  237. {asecli-0.8.2 → asecli-0.8.4}/tests/test_layout.py +0 -0
  238. {asecli-0.8.2 → asecli-0.8.4}/tests/test_layout_governance.py +0 -0
  239. {asecli-0.8.2 → asecli-0.8.4}/tests/test_layout_local_var_policy.py +0 -0
  240. {asecli-0.8.2 → asecli-0.8.4}/tests/test_material_gui_e2e.py +0 -0
  241. {asecli-0.8.2 → asecli-0.8.4}/tests/test_mcp_security.py +0 -0
  242. {asecli-0.8.2 → asecli-0.8.4}/tests/test_migrate_package.py +0 -0
  243. {asecli-0.8.2 → asecli-0.8.4}/tests/test_mutate.py +0 -0
  244. {asecli-0.8.2 → asecli-0.8.4}/tests/test_pass_blend.py +0 -0
  245. {asecli-0.8.2 → asecli-0.8.4}/tests/test_perf.py +0 -0
  246. {asecli-0.8.2 → asecli-0.8.4}/tests/test_property_presentation.py +0 -0
  247. {asecli-0.8.2 → asecli-0.8.4}/tests/test_roundtrip.py +0 -0
  248. {asecli-0.8.2 → asecli-0.8.4}/tests/test_schema_add.py +0 -0
  249. {asecli-0.8.2 → asecli-0.8.4}/tests/test_schema_samples.py +0 -0
  250. {asecli-0.8.2 → asecli-0.8.4}/tests/test_sg_export_sources.py +0 -0
  251. {asecli-0.8.2 → asecli-0.8.4}/tests/test_skill_install.py +0 -0
  252. {asecli-0.8.2 → asecli-0.8.4}/tests/test_supply_chain.py +0 -0
  253. {asecli-0.8.2 → asecli-0.8.4}/tests/test_usage_audit.py +0 -0
  254. {asecli-0.8.2 → asecli-0.8.4}/tests/test_wire_route_bridge.py +0 -0
  255. {asecli-0.8.2 → asecli-0.8.4}/tools/build_schema.py +0 -0
  256. {asecli-0.8.2 → asecli-0.8.4}/tools/check_document_governance.py +0 -0
  257. {asecli-0.8.2 → asecli-0.8.4}/tools/check_packed_executor_loc.py +0 -0
  258. {asecli-0.8.2 → asecli-0.8.4}/tools/check_regression_catalog.py +0 -0
  259. {asecli-0.8.2 → asecli-0.8.4}/tools/check_release_candidate.py +0 -0
  260. {asecli-0.8.2 → asecli-0.8.4}/tools/compare_build_artifacts.py +0 -0
  261. {asecli-0.8.2 → asecli-0.8.4}/tools/generate_sbom.py +0 -0
  262. {asecli-0.8.2 → asecli-0.8.4}/tools/supply_chain_check.py +0 -0
@@ -82,6 +82,8 @@ jobs:
82
82
  - run: uv venv .artifact-venv --python 3.12
83
83
  - run: uv pip install --python .artifact-venv/bin/python "dist/asecli-$ASECLI_VERSION-py3-none-any.whl"
84
84
  - run: .artifact-venv/bin/asecli parse tests/fixtures/step-antialiasing.function.txt
85
+ - name: Verify standalone wheel JSON contract
86
+ run: .artifact-venv/bin/python tools/independent_wheel_smoke.py
85
87
  - name: Smoke test packaged GUI installer
86
88
  run: |
87
89
  test_project="$RUNNER_TEMP/asecli-gui-smoke"
@@ -93,14 +95,3 @@ jobs:
93
95
  name: asecli-candidate-${{ github.sha }}
94
96
  path: dist/
95
97
  if-no-files-found: error
96
-
97
- cross-cli:
98
- needs: package
99
- uses: ./.github/workflows/cross-cli.yml
100
- with:
101
- sgcli_ref: ${{ vars.SGCLI_CANDIDATE_SHA }}
102
- asecli_artifact_name: asecli-candidate-${{ github.sha }}
103
- secrets:
104
- sgcli_read_ssh_key: ${{ secrets.SGCLI_READ_SSH_KEY }}
105
- permissions:
106
- contents: read
@@ -76,6 +76,8 @@ jobs:
76
76
  - run: uv venv .artifact-venv --python 3.12
77
77
  - run: uv pip install --python .artifact-venv/bin/python "dist/asecli-${ASECLI_VERSION}-py3-none-any.whl"
78
78
  - run: .artifact-venv/bin/asecli parse tests/fixtures/step-antialiasing.function.txt
79
+ - name: Verify standalone wheel JSON contract
80
+ run: .artifact-venv/bin/python tools/independent_wheel_smoke.py
79
81
  - run: .artifact-venv/bin/asecli install-skill --skill-root "$RUNNER_TEMP/codex-skills"
80
82
  - name: Smoke test packaged GUI installer
81
83
  run: |
@@ -89,19 +91,8 @@ jobs:
89
91
  path: dist/
90
92
  if-no-files-found: error
91
93
 
92
- cross-cli:
93
- needs: package
94
- uses: ./.github/workflows/cross-cli.yml
95
- with:
96
- sgcli_ref: ${{ vars.SGCLI_CANDIDATE_SHA }}
97
- asecli_artifact_name: asecli-candidate-${{ github.sha }}
98
- secrets:
99
- sgcli_read_ssh_key: ${{ secrets.SGCLI_READ_SSH_KEY }}
100
- permissions:
101
- contents: read
102
-
103
94
  publish:
104
- needs: [package, cross-cli]
95
+ needs: package
105
96
  if: ${{ vars.ASECLI_PYPI_ENABLED == 'true' }}
106
97
  runs-on: ubuntu-latest
107
98
  environment:
@@ -1,5 +1,12 @@
1
1
  # ASECLI 工程执行规则
2
2
 
3
+ ## 单仓独立边界
4
+
5
+ - ASECLI 任务只修改本仓库;不得因转换、测试失败或发布而自动修改、提交、推送 SGCLI。对方缺能力时记录协议需求,由用户另行授权对方任务。
6
+ - 运行、构建、必需测试、发布和安装不得依赖对方源码、开发目录、可执行文件、候选分支或跨仓凭据。
7
+ - 允许携带版本化公开 JSON Schema 静态快照;摘要用于本包完整性,不要求等于对方当前 main。未知语义继续失败关闭。
8
+ - 跨产品验收属于另行授权的外部黑盒编排,不成为本仓发布前置,不回写对方。
9
+
3
10
  ## 默认采用快速路径
4
11
 
5
12
  - 文档、注释、文案和不改变行为的配置修改,只检查相关 diff、格式与直接引用;不得启动 Unity/Tuanjie、截图、运行全量 pytest、发布治理或构建发布包。
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: asecli
3
- Version: 0.8.2
3
+ Version: 0.8.4
4
4
  Summary: Agent-native CLI for reading, modifying, validating and compiling Amplify Shader Editor assets
5
5
  Project-URL: Homepage, https://github.com/seeseeczl/ASECLI
6
6
  Project-URL: Repository, https://github.com/seeseeczl/ASECLI
@@ -28,7 +28,7 @@ Description-Content-Type: text/markdown
28
28
 
29
29
  AseCLI 是面向 AI Agent 的本地 CLI:离线读取、编辑和校验 ASE 节点图;通过运行中的 Unity/团结引擎与 MCP,让真实 ASE 创建节点、提供精排几何并重新生成 HLSL。Skill 提供跨 Agent 的操作规则,CLI 提供可验证的执行结果。
30
30
 
31
- 当前正式版:**[0.8.2](https://github.com/seeseeczl/ASECLI/releases/tag/v0.8.2)** · [PyPI](https://pypi.org/project/asecli/0.8.2/) · [Agent 操作手册](skills/asecli/SKILL.md) · [SG 转换后整理流程](skills/asecli/references/conversion-workflow.md)
31
+ 当前正式版:**[0.8.4](https://github.com/seeseeczl/ASECLI/releases/tag/v0.8.4)** · [PyPI](https://pypi.org/project/asecli/0.8.4/) · [Agent 操作手册](skills/asecli/SKILL.md) · [SG 转换后整理流程](skills/asecli/references/conversion-workflow.md)
32
32
 
33
33
  ASECLI 接收 SGCLI 生成的裸 `EditorGraphSpec v3`,并可把受支持的 ASE Shader 直接导出为 SGCLI 的裸 `sgcli.native.v3`。两个方向都只有“生产者 spec 原文件→消费者 `--spec`”;独立 report 与发布 receipt 都不进入创建输入,创建成功也不代表转换效果等价。
34
34
 
@@ -132,7 +132,7 @@ curl -fsSL https://raw.githubusercontent.com/seeseeczl/ASECLI/main/scripts/insta
132
132
  uv tool uninstall asecli
133
133
  ```
134
134
 
135
- 当前正式版本为 `0.8.2`(精确源 Alpha 混合、资源快照与转换认证加固),可从 [PyPI](https://pypi.org/project/asecli/0.8.2/) 或 [GitHub Release](https://github.com/seeseeczl/ASECLI/releases/tag/v0.8.2) 安装。历史版本见 [GitHub Releases](https://github.com/seeseeczl/ASECLI/releases),`v0.8.0` 保留为回滚点。
135
+ 当前正式版本为 `0.8.4`(ASE→SG 诊断收敛、Custom Function 原样证据与 MZGUI 呈现分层),可从 [PyPI](https://pypi.org/project/asecli/0.8.4/) 或 [GitHub Release](https://github.com/seeseeczl/ASECLI/releases/tag/v0.8.4) 安装。历史版本见 [GitHub Releases](https://github.com/seeseeczl/ASECLI/releases),`v0.8.3` 保留为回滚点。
136
136
 
137
137
  已知限制:真实 MCP 下,属性+纹理 v2 和 Reciprocal 降级 v2 的 create、manifest、validate、独立 recompile 已通过;SGCLI SphereMask v3 spec 在重载时仍可能返回 `node missing after reload: Radius` 并回滚。本次不承诺该 recipe 端到端可用,也不改变 SGCLI v2 默认值契约。
138
138
 
@@ -162,7 +162,7 @@ asecli --help
162
162
 
163
163
  ```bash
164
164
  shasum -a 256 -c SHA256SUMS
165
- uv tool install /path/to/asecli-0.8.2-py3-none-any.whl
165
+ uv tool install /path/to/asecli-0.8.4-py3-none-any.whl
166
166
  asecli --help
167
167
  ```
168
168
 
@@ -207,7 +207,7 @@ sgcli sg create Assets/ConvertedNew.shadergraph \
207
207
 
208
208
  `export-sg` 自动从源 Shader 向上识别 Unity/Tuanjie 工程;跨工程资源解析时显式传 `--target-project`。它强制生成 `<stem>.asecli-to-sgcli.spec.json`、`.report.json` 与 `.receipt.json`,同名即失败;receipt 只证明 spec/report 两份文件的提交状态与 SHA,不是中间交接包。命令不调用 SGCLI,也不生成 ASE 自有中间 JSON。未知节点、Master/Pass、外部属性或纹理 Importer 语义时只写规范报告,不写半成品 spec。反方向 `.asecli-to-sgcli.spec.json` 不能交给 ASECLI `create --spec`。
209
209
 
210
- ASECLI 随 wheel 发布自己拥有的 EditorGraphSpec v3 Schema,并固定一份 SGCLI `0.3.5` 的 `sgcli.native.v3` 生产快照;SGCLI 同样固定 ASECLI `0.8.2` 快照。双仓兼容检查会比较两组原始 Schema SHA-256,任何漂移都必须先升级生产者再放行。
210
+ ASECLI 随 wheel 发布自己的 EditorGraphSpec v3 Schema,以及源自 SGCLI `0.3.5` 的固定 `sgcli.native.v3` JSON 快照。快照 SHA-256 标识本包完整性与精确协议修订,不依赖对方当前分支或安装版本。构建、测试、发布与安装只使用 ASECLI,不拉取或执行 SGCLI 源码,不要求同步发布。`MultiplySourceAlpha` 等扩展仍要求实际消费者和目标 URP 支持,导出成功不代表旧消费者兼容。跨产品端到端验收是独立黑盒流程,不是本仓发布前置;本仓任务不自动跨仓修改。
211
211
 
212
212
  可用 `asecli contract editor-graph --version 3 --spec FILE` 在不连接 Editor 时执行权威 Schema/loader 并返回原文件 SHA。报告分开记录来源快照、发布前复核、生产者 Schema 与真实消费者读取状态。旧 `{graph,report}` wrapper 只允许按已登记形状显式迁移,且内层必须已经是 `sgcli.native.v3`;无版本 discriminator 的旧输入只报告 `legacy_format`,不得伪称已识别版本化 Schema:
213
213
 
@@ -340,9 +340,9 @@ asecli recompile Assets/Example.shader
340
340
  除显式 `--help` 保留人类可读文本外,stdout 恒为单行严格 JSON,agent 可直接解析。`--version` 也返回 JSON:
341
341
 
342
342
  ```json
343
- {"contract_version":1,"cli_version":"0.8.2","command":"parse","ok":true,"data":{"node_count":7}}
344
- {"contract_version":1,"cli_version":"0.8.2","command":"parse","ok":false,"error":{"code":"NOT_FOUND","message":"..."}}
345
- {"contract_version":1,"cli_version":"0.8.2","command":"version","ok":true,"data":{"version":"0.8.2"}}
343
+ {"contract_version":1,"cli_version":"0.8.4","command":"parse","ok":true,"data":{"node_count":7}}
344
+ {"contract_version":1,"cli_version":"0.8.4","command":"parse","ok":false,"error":{"code":"NOT_FOUND","message":"..."}}
345
+ {"contract_version":1,"cli_version":"0.8.4","command":"version","ok":true,"data":{"version":"0.8.4"}}
346
346
  ```
347
347
 
348
348
  常见错误码:`PARSE_ERROR`、`NOT_FOUND`、`USAGE_ERROR`、`SCHEMA_UNAVAILABLE`、`SCHEMA_VERSION_MISMATCH`、`VALIDATION_ERROR`、`PROPERTY_PRESENTATION_ERROR`、`LAYOUT_ERROR`、`CHECKSUM_FORMAT_ERROR`、`GUI_SUPPORT_ERROR`、`CUSTOM_GUI_ERROR`、`COMMENT_GROUP_ERROR`、`GRAPH_REVIEW_ERROR`、`SEMANTIC_MISMATCH`、`SG_EXPORT_BLOCKED`、`EXTERNAL_REFERENCE`、`SKILL_INSTALL_CONFLICT`、`SKILL_INSTALL_ERROR`、`WRITE_CONFLICT`、`WRITE_PARTIAL`、`UNSAFE_PATH`、`WRITE_ERROR`、`BRIDGE_ERROR`、`INTERNAL`。
@@ -4,7 +4,7 @@
4
4
 
5
5
  AseCLI 是面向 AI Agent 的本地 CLI:离线读取、编辑和校验 ASE 节点图;通过运行中的 Unity/团结引擎与 MCP,让真实 ASE 创建节点、提供精排几何并重新生成 HLSL。Skill 提供跨 Agent 的操作规则,CLI 提供可验证的执行结果。
6
6
 
7
- 当前正式版:**[0.8.2](https://github.com/seeseeczl/ASECLI/releases/tag/v0.8.2)** · [PyPI](https://pypi.org/project/asecli/0.8.2/) · [Agent 操作手册](skills/asecli/SKILL.md) · [SG 转换后整理流程](skills/asecli/references/conversion-workflow.md)
7
+ 当前正式版:**[0.8.4](https://github.com/seeseeczl/ASECLI/releases/tag/v0.8.4)** · [PyPI](https://pypi.org/project/asecli/0.8.4/) · [Agent 操作手册](skills/asecli/SKILL.md) · [SG 转换后整理流程](skills/asecli/references/conversion-workflow.md)
8
8
 
9
9
  ASECLI 接收 SGCLI 生成的裸 `EditorGraphSpec v3`,并可把受支持的 ASE Shader 直接导出为 SGCLI 的裸 `sgcli.native.v3`。两个方向都只有“生产者 spec 原文件→消费者 `--spec`”;独立 report 与发布 receipt 都不进入创建输入,创建成功也不代表转换效果等价。
10
10
 
@@ -108,7 +108,7 @@ curl -fsSL https://raw.githubusercontent.com/seeseeczl/ASECLI/main/scripts/insta
108
108
  uv tool uninstall asecli
109
109
  ```
110
110
 
111
- 当前正式版本为 `0.8.2`(精确源 Alpha 混合、资源快照与转换认证加固),可从 [PyPI](https://pypi.org/project/asecli/0.8.2/) 或 [GitHub Release](https://github.com/seeseeczl/ASECLI/releases/tag/v0.8.2) 安装。历史版本见 [GitHub Releases](https://github.com/seeseeczl/ASECLI/releases),`v0.8.0` 保留为回滚点。
111
+ 当前正式版本为 `0.8.4`(ASE→SG 诊断收敛、Custom Function 原样证据与 MZGUI 呈现分层),可从 [PyPI](https://pypi.org/project/asecli/0.8.4/) 或 [GitHub Release](https://github.com/seeseeczl/ASECLI/releases/tag/v0.8.4) 安装。历史版本见 [GitHub Releases](https://github.com/seeseeczl/ASECLI/releases),`v0.8.3` 保留为回滚点。
112
112
 
113
113
  已知限制:真实 MCP 下,属性+纹理 v2 和 Reciprocal 降级 v2 的 create、manifest、validate、独立 recompile 已通过;SGCLI SphereMask v3 spec 在重载时仍可能返回 `node missing after reload: Radius` 并回滚。本次不承诺该 recipe 端到端可用,也不改变 SGCLI v2 默认值契约。
114
114
 
@@ -138,7 +138,7 @@ asecli --help
138
138
 
139
139
  ```bash
140
140
  shasum -a 256 -c SHA256SUMS
141
- uv tool install /path/to/asecli-0.8.2-py3-none-any.whl
141
+ uv tool install /path/to/asecli-0.8.4-py3-none-any.whl
142
142
  asecli --help
143
143
  ```
144
144
 
@@ -183,7 +183,7 @@ sgcli sg create Assets/ConvertedNew.shadergraph \
183
183
 
184
184
  `export-sg` 自动从源 Shader 向上识别 Unity/Tuanjie 工程;跨工程资源解析时显式传 `--target-project`。它强制生成 `<stem>.asecli-to-sgcli.spec.json`、`.report.json` 与 `.receipt.json`,同名即失败;receipt 只证明 spec/report 两份文件的提交状态与 SHA,不是中间交接包。命令不调用 SGCLI,也不生成 ASE 自有中间 JSON。未知节点、Master/Pass、外部属性或纹理 Importer 语义时只写规范报告,不写半成品 spec。反方向 `.asecli-to-sgcli.spec.json` 不能交给 ASECLI `create --spec`。
185
185
 
186
- ASECLI 随 wheel 发布自己拥有的 EditorGraphSpec v3 Schema,并固定一份 SGCLI `0.3.5` 的 `sgcli.native.v3` 生产快照;SGCLI 同样固定 ASECLI `0.8.2` 快照。双仓兼容检查会比较两组原始 Schema SHA-256,任何漂移都必须先升级生产者再放行。
186
+ ASECLI 随 wheel 发布自己的 EditorGraphSpec v3 Schema,以及源自 SGCLI `0.3.5` 的固定 `sgcli.native.v3` JSON 快照。快照 SHA-256 标识本包完整性与精确协议修订,不依赖对方当前分支或安装版本。构建、测试、发布与安装只使用 ASECLI,不拉取或执行 SGCLI 源码,不要求同步发布。`MultiplySourceAlpha` 等扩展仍要求实际消费者和目标 URP 支持,导出成功不代表旧消费者兼容。跨产品端到端验收是独立黑盒流程,不是本仓发布前置;本仓任务不自动跨仓修改。
187
187
 
188
188
  可用 `asecli contract editor-graph --version 3 --spec FILE` 在不连接 Editor 时执行权威 Schema/loader 并返回原文件 SHA。报告分开记录来源快照、发布前复核、生产者 Schema 与真实消费者读取状态。旧 `{graph,report}` wrapper 只允许按已登记形状显式迁移,且内层必须已经是 `sgcli.native.v3`;无版本 discriminator 的旧输入只报告 `legacy_format`,不得伪称已识别版本化 Schema:
189
189
 
@@ -316,9 +316,9 @@ asecli recompile Assets/Example.shader
316
316
  除显式 `--help` 保留人类可读文本外,stdout 恒为单行严格 JSON,agent 可直接解析。`--version` 也返回 JSON:
317
317
 
318
318
  ```json
319
- {"contract_version":1,"cli_version":"0.8.2","command":"parse","ok":true,"data":{"node_count":7}}
320
- {"contract_version":1,"cli_version":"0.8.2","command":"parse","ok":false,"error":{"code":"NOT_FOUND","message":"..."}}
321
- {"contract_version":1,"cli_version":"0.8.2","command":"version","ok":true,"data":{"version":"0.8.2"}}
319
+ {"contract_version":1,"cli_version":"0.8.4","command":"parse","ok":true,"data":{"node_count":7}}
320
+ {"contract_version":1,"cli_version":"0.8.4","command":"parse","ok":false,"error":{"code":"NOT_FOUND","message":"..."}}
321
+ {"contract_version":1,"cli_version":"0.8.4","command":"version","ok":true,"data":{"version":"0.8.4"}}
322
322
  ```
323
323
 
324
324
  常见错误码:`PARSE_ERROR`、`NOT_FOUND`、`USAGE_ERROR`、`SCHEMA_UNAVAILABLE`、`SCHEMA_VERSION_MISMATCH`、`VALIDATION_ERROR`、`PROPERTY_PRESENTATION_ERROR`、`LAYOUT_ERROR`、`CHECKSUM_FORMAT_ERROR`、`GUI_SUPPORT_ERROR`、`CUSTOM_GUI_ERROR`、`COMMENT_GROUP_ERROR`、`GRAPH_REVIEW_ERROR`、`SEMANTIC_MISMATCH`、`SG_EXPORT_BLOCKED`、`EXTERNAL_REFERENCE`、`SKILL_INSTALL_CONFLICT`、`SKILL_INSTALL_ERROR`、`WRITE_CONFLICT`、`WRITE_PARTIAL`、`UNSAFE_PATH`、`WRITE_ERROR`、`BRIDGE_ERROR`、`INTERNAL`。
@@ -0,0 +1,94 @@
1
+ # 对抗性审计报告:ASECLI / SGCLI 独立性与跨仓耦合
2
+
3
+ > 生成时间:2026-09-14 13:28:14(Asia/Shanghai)
4
+ > 落盘根目录:/Users/long/GitHub/ASECLI
5
+ > Skill:adversarial-audit
6
+ > 关联优化计划:2026-09-14-132814-optimization-plan.md
7
+
8
+ ## 审计边界
9
+
10
+ - 用户要求:各自独立开发、构建、测试、发布、安装;可以按对方公开规范产出 JSON,不互相引用实现代码,不因一方任务默认跨仓修改。
11
+ - 只读检查两个仓库的源码、依赖、打包、工作流、契约、跨仓测试及技能。仅新增本报告与计划,不修改 SGCLI,不执行发布。
12
+ - 当前基线:ASECLI `89eb9ae22d94a8d056c7fd28b5923d7dd513ac69`;SGCLI `488776fe996d226d8900dbe69e0547737c9986b4`。本轮开始时既有修复已进入新的 HEAD;此前对旧候选 Schema 不一致的观察不能当作当前两仓仍失配的证据。
13
+ - 方法:静态调用/依赖追踪、工作流依赖图与失败条件检查。没有运行两仓全量测试、隔离安装或远端 CI;不将静态未发现视为任意动态环境下的绝对证明。
14
+
15
+ ## 威胁与失败模型
16
+
17
+ - 资产:独立 CLI 运行、可重复发布、JSON 兼容性、仓库写入边界。
18
+ - 对方仓库可能暂不可访问、存在未提交改动、接口加性升级或主分支变化。
19
+ - 任一方应能离线验证本地固定协议,而不要求安装/获取对方实现。
20
+ - 不支持的语义必须拒绝并生成诊断,不通过跨仓自动修复或弱化验证掩盖。
21
+ - 最贵失败:自身代码无变化却无法发布;为解锁发布误改对方;混装测试漏掉真实运行依赖。
22
+
23
+ ## Findings 汇总
24
+
25
+ | ID | 严重度 | 标题 | 证据等级 | 任务 |
26
+ | --- | --- | --- | --- | --- |
27
+ | AA-COUP-001 | P1 | 默认 CI / ASECLI 发布依赖对方源码与跨仓权限 | 已验证(静态) | AA-OPT-001 |
28
+ | AA-COUP-002 | P1 | 两端候选 Schema 字节相等被当作发布兼容要求 | 已验证(静态) | AA-OPT-002 |
29
+ | AA-COUP-003 | P2 | 集成测试代码绑定兄弟仓库与双方工作树状态 | 已验证(静态) | AA-OPT-003 |
30
+ | AA-COUP-004 | P2 | 双 wheel 混装不足以证明单工具运行独立性 | 已验证(覆盖缺口) | AA-OPT-004 |
31
+
32
+ ## Findings 详情
33
+
34
+ ### [P1] AA-COUP-001 — 将跨仓检查从单仓必需发布路径分离
35
+
36
+ - 证据:ASECLI `.github/workflows/publish.yml:103-104` 的 publish 需要 `[package, cross-cli]`;cross-cli 从对方仓库取得代码、构建 wheel、执行 SGCLI/scripts 内的校验实现,并要求对方 commit 与 SSH secret。ASECLI `.github/workflows/ci.yml:97` 默认接入相同检查。
37
+ - SGCLI `.github/workflows/ci.yml:103-108` 在 main / tag CI 接入跨仓检查,使用 ASECLI 浮动 `main`;`.github/workflows/cross-cli.yml:36-38` checkout 对方。这里只证明 SGCLI 默认 CI 被绑定,未发现同等的 SGCLI PyPI publish job,不扩大为该发布机制已验证。
38
+ - 触发:对方仓库/权限不可用,或对方 main 变化导致矩阵不通过。
39
+ - 影响:ASECLI 正式发布被阻断;SGCLI 同一提交的 CI 可受对方 main 影响,违反独立维护要求。
40
+ - 两仓 `tests/test_cross_cli_workflow.py` 还强制检查这种关联存在;ASECLI 测试第 18 行直接要求 publish 的跨仓 needs。仅删 workflow 引用会导致本地测试失败,需在本仓同时更新对应测试。
41
+ - 修复方向:单仓发布依赖自身检查、固定协议夹具和独立 wheel smoke;可选跨产品黑盒测试移出单仓必需发布路径,最好独立测试工程管理。分别在每个仓库执行,不自动联动。
42
+ - 关联:AA-OPT-001。
43
+
44
+ ### [P1] AA-COUP-002 — 区分协议快照完整性与跨版本兼容性
45
+
46
+ - 证据:SGCLI `scripts/cross_cli_wheels.py:74-105` 读取两包四份 Schema 并直接比较 `consumer_raw == producer_raw`;`scripts/check_cross_cli_contracts.py:370-398` 将相等性纳入 ok。两仓 README 明确要求同步双方候选快照。
47
+ - 触发:对方只改 Schema 排版、说明或添加兼容字段,生产者仍产生被目标支持的 JSON,但字节摘要不同。
48
+ - 影响:语义兼容也要求同步更新/发布;Schema 名称保持 v3 时又增添新能力,会进一步造成版本标签不能充分表达能力集合。
49
+ - 修复方向:本包固定 Schema 的自完整性 SHA 校验保留;不要要求始终等于对方当前分支。以明确协议修订/能力集合和正负 JSON 夹具验证支持范围。新能力不能因单方发布就声明所有旧消费者可用。
50
+ - 注意:随包携带静态 JSON Schema 是允许的协议关联,不是运行代码依赖,不应删除。
51
+ - 关联:AA-OPT-002。
52
+
53
+ ### [P2] AA-COUP-003 — 集成工具仍读取另一仓库内部结构
54
+
55
+ - 证据:SGCLI `scripts/check_cross_cli_contracts.py:52` 读取兄弟仓库源码 Schema;第 344 行默认 `../ASECLI`,第 370-377、425-428 行依赖双方仓库身份和干净工作树;`scripts/e2e_sgcli_to_ase.py:34` 默认使用 `../ASECLI/.venv/bin/asecli`。
56
+ - 触发:只克隆一个仓库、另一个仓库目录不同,或另一个任务有未提交布局改动。
57
+ - 影响:集成验证依赖对方开发目录,不符合“工具仓库之间不保留实现关联”的强独立目标。当前脚本以读取/执行为主,未据此认定会自动编辑另一仓源码。
58
+ - 修复方向:两个工具仓库各保留自身协议测试;跨产品场景搬到单独、显式运行的黑盒测试工程,只接受已发布包/可执行文件和 JSON,不读取对方 src 或 git 状态。不要为通过测试自动 stash/commit 对方。
59
+ - 关联:AA-OPT-003。
60
+
61
+ ### [P2] AA-COUP-004 — 增加仅安装自身的运行独立性反例
62
+
63
+ - 证据:SGCLI `scripts/cross_cli_wheels.py:46-67` 把两个 wheel 安装到同一个 venv;这类测试即使通过,也不能排除未来代码隐式使用对方包。
64
+ - 边界:两仓现有 package job 已有单 wheel smoke,这是有效局部证据;缺口在完整的独立导出/校验/失败路径与跨仓调用禁止验证,不是“完全没有独立测试”。
65
+ - 触发:后续新增对方 import、PATH 子进程调用或开发目录读取,但混装测试依然通过。
66
+ - 修复方向:分别在只安装自身 wheel、无兄弟目录、对方不在 PATH 的隔离环境验证本工具导出与 JSON 校验;加静态禁止互相 import/路径引用检查。验证非法或不支持 JSON 仍失败关闭。
67
+ - 关联:AA-OPT-004。
68
+
69
+ ## 当前没有发现的运行代码耦合
70
+
71
+ - 两边 `pyproject.toml` 的运行 `dependencies=[]`,wheel 配置只打包自身代码与自身携带的静态数据。
72
+ - 检查两边 src Python,未发现互相 import、子进程启动对方 CLI、动态导入对方或对方开发目录路径引用。
73
+ - 两边 contracts.py 从各自包资源加载 Schema,`package`/`version` 字符串是元数据,不是安装依赖。未发现互相链接的 tracked symlink/submodule。
74
+ - ASECLI 生成 JSON,SGCLI 自己读取并验证;转换报告规则分别实现。相似规则/重复校验不等于共享可执行模块。
75
+ - SGCLI 资源证据重查需要 JSON 所指向的源/目标图片和 meta 可访问,这是资源可移植性限制,不是必须安装 ASECLI。不得为了独立性直接删除证据校验。
76
+ - MultiplySourceAlpha 还依赖目标工程的对应 URP 能力,这是引擎能力依赖,不是 CLI 互相依赖。
77
+
78
+ ## 技能与操作边界
79
+
80
+ - 两端 authoring 技能已经写明 CLI 不调用对方;联合 shader-conversion 技能描述先后调用两个独立 CLI,这属于用户级编排,不等于 CLI 内部调用。
81
+ - SGCLI 的 install-skill 分发联合转换/等价技能,但不分发 ASECLI 实现或 ASECLI authoring skill;没有据此认定代码耦合。
82
+ - 当前资料包含两边配套升级、同步候选的历史流程;尚缺清楚的单仓维修边界。遵循用户本轮新要求:后续一仓任务不能默认改另一仓,发现对方缺能力只输出协议需求/诊断,另行授权对方任务。
83
+ - 本轮只提出在各自 AGENTS/技能中补充此规则的任务,不跨仓落盘规则、不更新全局记忆。
84
+
85
+ ## 测试与观测缺口
86
+
87
+ - 本次未重新执行独立 wheel 安装、远端 CI、Unity 或渲染。
88
+ - 后续应记录本工具版本、支持的协议修订与能力、生产校验和消费者验收阶段,不以两仓同时升级为完成信号。
89
+
90
+ ## 残留风险与总评
91
+
92
+ 结论:运行代码层目前未发现互相依赖;开发测试与发布流程仍明显耦合,阻塞“完全独立维护/发布”目标。JSON 协议必须有约定,但不要求实现共享或发布锁步。不得用删除语义校验、放宽未知字段、伪造报告的方式解耦。
93
+
94
+ 实施顺序:先在 ASECLI 单仓整改并验证独立发布;SGCLI 的整改留给其独立任务。本报告不执行任何整改、提交或发布。
@@ -0,0 +1,56 @@
1
+ # 对抗性审计优化计划:ASECLI / SGCLI 各自独立
2
+
3
+ > 生成时间:2026-09-14 13:28:14(Asia/Shanghai)
4
+ > 落盘根目录:/Users/long/GitHub/ASECLI
5
+ > 关联报告:2026-09-14-132814-audit-report.md
6
+
7
+ ## 1. 执行摘要
8
+
9
+ P0=0、P1=2、P2=2、P3=0。运行代码未发现互相依赖,独立维护/发布目标尚不通过。保留公开 JSON 协议、严格验证和失败关闭,移除强制跨仓发布与源码目录关联。
10
+
11
+ 本轮仅审计。后续严格分两次执行:ASECLI 任务只修改 ASECLI;SGCLI 任务只修改 SGCLI。任何迁移到第三方集成测试工程也需另行确定目标和授权,不在本轮创建。
12
+
13
+ ## 2. 修复与加固任务
14
+
15
+ | 任务 | 优先级 | 来源 | 内容 | 验收标准 | 依赖 | 风险/回滚 |
16
+ | --- | --- | --- | --- | --- | --- | --- |
17
+ | AA-OPT-001 | P1 | AA-COUP-001 | 各仓各自移除默认 CI/发布对另一仓 checkout/build 的必需依赖;同步本仓 workflow 回归 | 无对方源码、凭据和候选 SHA 时,自身测试/打包/发布路径正常;不删除本仓语义门禁 | 分仓授权 | 恢复本仓 workflow,不操作对方 |
18
+ | AA-OPT-002 | P1 | AA-COUP-002 | 本地固定协议修订及能力集;自完整性摘要与跨版本兼容分开 | 目标 Schema 兼容排版/描述变化不迫使双方同时发布;未知能力仍拒绝;协议声明对应夹具 | 无需对方代码 | 保留旧协议支持与不可变快照 |
19
+ | AA-OPT-003 | P2 | AA-COUP-003 | 移出兄弟仓库源码、虚拟环境和 git 状态相关脚本;跨产品测试另行管理 | 单仓克隆可开发;任何本仓必需命令不访问 ../另一仓;外部黑盒测试仅依赖发布接口 | 先列迁移范围,分别授权 | 保留可追溯历史,不删除用户资产 |
20
+ | AA-OPT-004 | P2 | AA-COUP-004 | 仅自身 wheel 的隔离导出、消费校验和负向回归 | 环境无对方模块、命令、源码,全部本仓相关路径可运行;新增耦合被门禁抓到 | 无 | 不以混装测试替代隔离证明 |
21
+ | AA-OPT-005 | P2 | 用户新边界 | 在各自仓库规则/技能明确“单仓任务不跨仓修改” | 对方缺能力时生成接口问题说明,停止于本仓边界;任何跨仓写入另行授权 | 各仓单独执行 | 保留转换编排能力,不禁止只读协议查阅 |
22
+
23
+ ## 3. 测试补强任务
24
+
25
+ - AA-TEST-001:自身 wheel 安装在独立 venv,PATH 无另一 CLI,执行版本、导出、Schema 校验、失败报告;检查未导入另一包。
26
+ - AA-TEST-002:冻结协议正负 JSON 夹具,检查节点/资源/混合/报告语义;协议扩展不自动意味着旧消费者支持。
27
+ - AA-TEST-003:CI 静态检查不再要求另一仓 checkout、credential、branch、SHA、wheel 或脚本;对方全部不可用时本仓必要门禁仍可通过。
28
+ - AA-TEST-004:跨仓目录读写/互相 import/调用负例能被独立性门禁识别;集成测试不得掩盖本工具缺依赖。
29
+
30
+ ## 4. 观测与运维任务
31
+
32
+ - AA-OBS-001:发布说明列出支持的协议修订、能力限制,不承诺另一 CLI 已同步升级。
33
+ - AA-OBS-002:可选外部兼容矩阵记录两边发布版本与 JSON SHA;结果不替代自身门禁,不回写两仓。
34
+ - AA-OBS-003:任务结束列明实际写入的单仓范围,确认另一仓未被该任务修改。
35
+
36
+ ## 5. 发布门禁
37
+
38
+ - [ ] 本仓必需检查不执行另一仓代码、不要求另一仓权限或可用性。
39
+ - [ ] 只安装本工具即可执行相关导出/校验。
40
+ - [ ] 固定 JSON 规范和语义负向测试仍严格有效。
41
+ - [ ] 能独立构建、安装、回滚;报告已区分离线与 Editor/渲染证据。
42
+ - [ ] 没有修改另一仓库;对方任务独立安排。
43
+
44
+ ## 6. 未映射项
45
+
46
+ 无。静态 JSON Schema、规则实现及名称中的对方标识允许保留;它们是格式适配,不应为“无关联代码”而删除协议校验。联合工作流技能是否移至独立分发位置可另行讨论,本轮不新增运行依赖或架构项目。
47
+
48
+ ## 7. ASECLI 单仓整改回执
49
+
50
+ - 已移除 ASECLI CI / publish 的 cross-cli job,publish 仍依赖自身 verify→package 的完整链路;删除本仓 `.github/workflows/cross-cli.yml`(Git 可恢复),不再 checkout 对方、使用对方 SSH secret/候选 SHA 或运行对方脚本。没有修改 GitHub 远程变量、Secret 或 SGCLI。
51
+ - 改为自身固定 Schema/语义正负回归及独立 wheel smoke;保留本包快照 SHA 校验,不读取另一仓实时 Schema。README/contracts 注释明确版本只是快照来源,不是运行依赖。
52
+ - 新增 `tools/independent_wheel_smoke.py`:仅安装 ASECLI wheel、检查 SGCLI 模块不可用,子进程 PATH 仅当前 venv,清除 PYTHONPATH,在临时工程运行版本、契约、实际 export-sg、非法 spec 拒绝及 CustomEditor 失败报告检查。CI 和 publish 的 package job 均运行该脚本。
53
+ - 本仓 AGENTS、ASECLI Skill 和已安装 `.agents/skills/asecli/SKILL.md` 同步单仓边界;不更新 SGCLI Skill、不修改对方仓库。跨仓静态回归改为禁止运行源码互相 import/固定开发目录和 CI 跨仓引用。
54
+ - 验证:相关测试 64 passed;CI governance 与 regression catalog 通过;独立 wheel 实测返回 `standalone_wheel=true`、`consumer_executed=false`;git diff --check 通过。隔离产物位于 `/tmp/asecli-independent-wheel.T0VXC8`。
55
+ - 此隔离 wheel 沿用当前工作树版本 0.8.2,仅用于候选测试,不是新版本正式发布,也没有替换本机 CLI。未启动 Editor,未提交/推送/发布。本轮移除的跨仓 YAML 是唯一删除的配置文件,可由 Git 历史恢复。
56
+ - 完成范围:AA-OPT-001/002/004/005 的 ASECLI 部分;AA-OPT-003 在 ASECLI 中的对方源码执行入口已移除。SGCLI 自有 CI、脚本与规则保持原样,其任务仍待独立执行,不能声明两个仓库都已解耦。
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "asecli"
3
- version = "0.8.2"
3
+ version = "0.8.4"
4
4
  description = "Agent-native CLI for reading, modifying, validating and compiling Amplify Shader Editor assets"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.10"
@@ -11,6 +11,9 @@ description: Create, modify, validate, and strictly lay out Amplify Shader Edito
11
11
 
12
12
  ## 与 SGCLI 的双向 JSON 直连
13
13
 
14
+ - 单仓维护:ASECLI 修改、检查、发布、安装不自动修改 SGCLI;对方缺能力时报告协议需求,由用户另行授权对方任务。
15
+ - 两 CLI 无运行代码依赖。用随包固定的公开 JSON Schema 自行验证,快照摘要不要求跟随对方 main。用户显式编排的端到端转换不是 ASECLI 开发或发布的前置条件。
16
+
14
17
  - SG→ASE:`sgcli convert Graph.shadergraph --out-dir ./out` 生成裸 `Graph.sgcli-to-asecli.spec.json`、独立 report 和发布 receipt;`asecli create Assets/Graph.shader --spec ./out/Graph.sgcli-to-asecli.spec.json` 只直接消费 spec 原文件。
15
18
  - ASE→SG:`asecli export-sg Graph.shader --out-dir ./out` 生成裸 `Graph.asecli-to-sgcli.spec.json`(`sgcli.native.v3`)、独立 report 和发布 receipt;SGCLI `sg create --spec` 只直接消费 spec 原文件。
16
19
  - 不生成 `asecli.ase-graph.*` 中间 JSON,不调用 SGCLI,不使用 wrapper、`.graph` 解包、jq、Agent 改写或一次性 translator。
@@ -19,6 +22,16 @@ description: Create, modify, validate, and strictly lay out Amplify Shader Edito
19
22
  - 旧 `{graph,report}` wrapper 只经 `asecli migrate-package OLD --out-dir DIR --extract-sg-spec` 按登记形状显式提取;只接受内层 `sgcli.native.v3`,未知或 v2 wrapper 失败关闭。无版本 discriminator 时记录 `legacy_format`,不能声称识别出 legacy schema 版本。
20
23
  - 报告中的 `source_snapshot_sha256/source_recheck_sha256` 必须一致;`producer_schema_validated` 与 `consumer_loaded` 分开记录,未实际调用 SGCLI 时后者保持 `not_run`。
21
24
 
25
+ ### 导出阻断的确定性处理
26
+
27
+ - 先核对 CLI 路径/版本和源 SHA;当前 `.shader`、历史 `.bak`、旧 report 不可混为同一次转换证据。
28
+ - 新版失败返回的顶层 `data` 包含 `blockers`、`blocker_count`、`unverified_checks`、源快照与 `surface_semantics`。它是本次检测清单,不保证穷尽所有潜在问题;旧版没有这些字段时读取 `report_json`,不要猜测只有一个阻断。
29
+ - `ALPHA_MODULATE_TARGET_CAPABILITY_REQUIRED` 表示末端表达式不能安全折叠到 URP 的 half AlphaModulate;读取 `required_target_capabilities`,不得把 `MultiplySourceAlpha` 用于需要保留背景 Alpha 的源 Shader。
30
+ - 上游 Custom Function 作为目标 Custom Function 原样交接;用 `custom_function_manifest` 核对节点、精度和规范化函数载荷 SHA,不因 Agent 无法解释函数数学意义而拒绝。
31
+ - 已确认的 `MZGUI.MZGUI`、Tooltip/Foldout/HelpBox 只影响 Inspector 呈现,列在 `presentation_warnings`,不阻断渲染语义交接。其他未知 Custom ShaderGUI 仍可能有材质副作用并失败关闭。
32
+ - `retry_unchanged_input=false` 时不要重复相同导出、猜命令或找强制开关。报告缺失能力并停止;SGCLI 的新增能力必须通过公开 JSON 契约另行交接,不跨仓修补。
33
+ - 原生 `.shadergraph` 虽然使用 JSON 序列化,但不是 `sgcli.native.v3` 创建 spec。只有本次命令成功并核对 spec/report/receipt 完整提交与 SHA,才能称“导出成功”;这仍不等于 Editor 编译或最终效果一致已验收。
34
+
22
35
  ## Agent 兼容性
23
36
 
24
37
  本 Skill 遵循通用 Agent Skills 目录结构:标准 YAML frontmatter、`SKILL.md` 正文和相对路径引用。它只要求 Agent 能运行本地 shell 命令并读取 ASECLI 的单行 JSON,不依赖 Codex、Claude Code、Cursor、Gemini CLI 或 GitHub Copilot 的专属工具名、权限模型或消息格式。
@@ -1,3 +1,3 @@
1
1
  """AseCLI — agent-native toolkit for Amplify Shader Editor assets."""
2
2
 
3
- __version__ = "0.8.2"
3
+ __version__ = "0.8.4"
@@ -106,24 +106,24 @@ def cmd_export_sg(args) -> dict:
106
106
  raise ValueError(f'resource changed before publication: {file}')
107
107
  except ExportError as exc:
108
108
  internal = exc.report
109
- _write_failure_report(
109
+ failure_report = _write_failure_report(
110
110
  source, spec_path, report_path, internal, str(exc),
111
111
  source_raw=source_raw, schema_status=schema_status,
112
112
  )
113
113
  raise CliError(
114
114
  "SG_EXPORT_BLOCKED",
115
115
  str(exc),
116
- {"report_json": str(report_path)},
116
+ _failure_details(report_path, internal, failure_report),
117
117
  ) from exc
118
118
  except (OSError, ValueError, RuntimeError, json.JSONDecodeError) as exc:
119
- _write_failure_report(
119
+ failure_report = _write_failure_report(
120
120
  source, spec_path, report_path, internal, str(exc),
121
121
  source_raw=source_raw, schema_status=schema_status,
122
122
  )
123
123
  raise CliError(
124
124
  "SG_EXPORT_BLOCKED",
125
125
  str(exc),
126
- {"report_json": str(report_path)},
126
+ _failure_details(report_path, internal, failure_report),
127
127
  ) from exc
128
128
  write_result = _write_pair(spec_path, spec, report_path, report)
129
129
  return {
@@ -175,7 +175,7 @@ def _write_failure_report(
175
175
  *,
176
176
  source_raw: bytes,
177
177
  schema_status: str,
178
- ) -> None:
178
+ ) -> dict:
179
179
  if report_path.exists():
180
180
  raise CliError("WRITE_CONFLICT", f"output already exists: {report_path}")
181
181
  report = build_public_report(
@@ -189,6 +189,35 @@ def _write_failure_report(
189
189
  producer_schema_validated=schema_status,
190
190
  )
191
191
  _write_new(report_path, report)
192
+ return report
193
+
194
+
195
+ def _failure_details(report_path: Path, internal: dict | None, report: dict) -> dict:
196
+ """Agent-facing diagnostics, separate from the fixed consumer report schema."""
197
+ internal = internal or {}
198
+ blockers = [dict(item, classification="semantic") for item in internal.get("diagnostics", [])]
199
+ blockers.extend(dict(item) for item in internal.get("degradations", []))
200
+ warnings = [dict(item) for item in internal.get("presentation_warnings", [])]
201
+ return {
202
+ "report_json": str(report_path),
203
+ "spec_written": False,
204
+ "receipt_written": False,
205
+ "source": report["source"],
206
+ "blockers": blockers,
207
+ "blocker_count": len(blockers),
208
+ "blocker_scope": "detected_in_this_run_not_exhaustive",
209
+ "presentation_warnings": warnings,
210
+ "warning_count": len(warnings),
211
+ "custom_function_manifest": internal.get("custom_function_manifest", []),
212
+ "required_target_capabilities": (internal.get("surface_semantics") or {}).get(
213
+ "required_target_capabilities"
214
+ ),
215
+ "unverified_checks": [name for name, check in report["checks"].items()
216
+ if check["status"] != "verified"],
217
+ "surface_semantics": internal.get("surface_semantics"),
218
+ "retry_unchanged_input": False,
219
+ "next_action": "Inspect all blockers and report evidence; do not force export, substitute a .shadergraph, or edit the source to bypass validation",
220
+ }
192
221
 
193
222
 
194
223
  def _assert_source_unchanged(source: Path, snapshot: bytes, phase: str) -> bytes:
@@ -11,6 +11,9 @@ from .schema_validation import validate_schema
11
11
 
12
12
  EDITOR_GRAPH_V3 = "contracts/editor-graph-spec.v3.schema.json"
13
13
  SGCLI_NATIVE_V3_SNAPSHOT = "contracts/sgcli.native.v3.schema.json"
14
+ # Provenance of the bundled JSON document, not a runtime dependency or a
15
+ # requirement to match another repository's current checkout. The SHA pins
16
+ # this exact supported protocol revision independently of CLI releases.
14
17
  SGCLI_NATIVE_CONSUMER = {
15
18
  "package": "sgcli",
16
19
  "version": "0.3.5",
@@ -8,6 +8,7 @@ from pathlib import Path
8
8
  from typing import Any
9
9
 
10
10
  from .report_semantics import check_evidence
11
+ from .report_presentation import presentation_degradations
11
12
 
12
13
 
13
14
  CHECK_RULES = {
@@ -76,6 +77,7 @@ def build_public_report(
76
77
  "blend_equation": "verified" if blend_passed else "unknown",
77
78
  }
78
79
  internal_degradations = (internal or {}).get('degradations', [])
80
+ presentation_warnings = (internal or {}).get('presentation_warnings', [])
79
81
  if internal_degradations:
80
82
  check_status['properties'] = 'unsupported'
81
83
  checks = {
@@ -125,6 +127,7 @@ def build_public_report(
125
127
  + str(item.get('impact', 'Inspector behavior is unproven'))
126
128
  + '; details=' + json.dumps(item.get('details', []), ensure_ascii=False),
127
129
  })
130
+ degradations.extend(presentation_degradations(presentation_warnings, source, spec_path))
128
131
  if failure:
129
132
  degradations.append({
130
133
  "rule": "SEM-REPORT-001",
@@ -13,13 +13,12 @@ from .model import (
13
13
  )
14
14
  from .nodes import convert_node
15
15
  from .sources import compiled_properties, load_asset_map
16
- from .evidence import inspector_degradations, record_port, validate_template_passes
16
+ from .evidence import inspector_degradations, record_custom_functions, record_port, validate_template_passes
17
17
  from .surface_semantics import normalize_surface_outputs
18
18
  from .reconciliation import (
19
19
  groups, reconcile_shaderlab_properties, unique_properties, verify_texture_dependencies,
20
20
  )
21
21
 
22
-
23
22
  def build_candidate(
24
23
  source_path,
25
24
  target_project,
@@ -124,6 +123,7 @@ def build_candidate(
124
123
  for node in nodes:
125
124
  for target_id in node.source_ids:
126
125
  edges.append(SemanticEdge(node.target_id, 0, target_id, -1))
126
+ record_custom_functions(nodes, report)
127
127
  nodes, edges = normalize_surface_outputs(nodes, edges, target_spec, mappings, report, text)
128
128
  groups_spec = groups(ase, mappings, diagnostics)
129
129
  report["output_bindings"] = [
@@ -3,10 +3,29 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  import re
6
+ import hashlib
7
+ import json
6
8
 
9
+ from .alpha_modulate import _strip_comments
7
10
  from .model import MASTER_TYPE, URP_UNLIT_GUID, URP_UNLIT_PASSES, diagnostic
8
11
 
9
12
 
13
+ def record_custom_functions(nodes, report):
14
+ manifest = []
15
+ for node in nodes:
16
+ if node.target_type != "custom-function" or node.function is None:
17
+ continue
18
+ canonical = json.dumps(node.function, ensure_ascii=False, sort_keys=True,
19
+ separators=(",", ":")).encode("utf-8")
20
+ manifest.append({
21
+ "source_node_id": node.source_id, "target_node_id": node.target_id,
22
+ "function_sha256": hashlib.sha256(canonical).hexdigest(),
23
+ "precision": node.settings.get("precision", "Inherit"),
24
+ "mapping": "preserved_custom_function_payload",
25
+ })
26
+ report["custom_function_manifest"] = manifest
27
+
28
+
10
29
  def validate_template_passes(ase, master, diagnostics, report):
11
30
  masters = [node for node in ase.graph.nodes if node.type_name == MASTER_TYPE]
12
31
  passes = {node.raw_fields[15] for node in masters if len(node.raw_fields) > 15}
@@ -38,18 +57,39 @@ def inspector_degradations(ase, properties, report):
38
57
  match = re.search(rf"(?m)^\s*(?P<attrs>(?:\[[^\]\r\n]*\]\s*)*){re.escape(name)}\s*\(", ase.prefix)
39
58
  present = [kind for kind in attributes if match and f"[{kind}" in match.group("attrs")]
40
59
  if present:
41
- report["degradations"].append({
60
+ report["presentation_warnings"].append({
42
61
  "source": {"property": name}, "code": "INSPECTOR_METADATA_NOT_MIGRATED",
43
62
  "details": present, "impact": "Property data is preserved; ASE Inspector UI behavior is not migrated",
63
+ "classification": "presentation_only",
64
+ "source_attributes": match.group("attrs").strip(),
65
+ "material_side_effects": "none",
44
66
  })
45
- custom_gui = sorted({node.raw_fields[9] for node in ase.graph.nodes
67
+ graph_gui = {node.raw_fields[9] for node in ase.graph.nodes
46
68
  if node.type_name == MASTER_TYPE and len(node.raw_fields) > 9
47
69
  and node.raw_fields[6] == "True"
48
- and node.raw_fields[9] not in {"", "UnityEditor.ShaderGraphUnlitGUI"}})
49
- if custom_gui:
70
+ and node.raw_fields[9] not in {"", "UnityEditor.ShaderGraphUnlitGUI"}}
71
+ # Compiled ShaderLab may disagree with the ASE graph. Neither declaration
72
+ # can be ignored when an unknown GUI can alter keywords/material state.
73
+ shaderlab = ase.prefix.rsplit("/*ASEBEGIN", 1)[0]
74
+ compiled_gui = set(re.findall(r'\bCustomEditor\s+"([^"]+)"', _strip_comments(shaderlab) or ""))
75
+ custom_gui = (graph_gui | compiled_gui) - {"", "UnityEditor.ShaderGraphUnlitGUI"}
76
+ known_presentation = sorted(custom_gui & {"MZGUI.MZGUI"})
77
+ unknown_gui = sorted(custom_gui - {"MZGUI.MZGUI"})
78
+ if known_presentation:
79
+ report["presentation_warnings"].append({
80
+ "source": {"file": str(report["source"]["path"])},
81
+ "code": "CUSTOM_INSPECTOR_PRESENTATION_NOT_MIGRATED",
82
+ "details": known_presentation,
83
+ "classification": "presentation_only",
84
+ "material_side_effects": "none",
85
+ "impact": "MZGUI Inspector styling is not migrated; Shader properties and runtime graph semantics are unchanged",
86
+ })
87
+ if unknown_gui:
50
88
  report["degradations"].append({
51
89
  "source": {"file": str(report["source"]["path"])}, "code": "CUSTOM_INSPECTOR_NOT_MIGRATED",
52
- "details": custom_gui,
90
+ "details": unknown_gui,
91
+ "classification": "custom_shader_gui",
92
+ "material_side_effects": "unproven",
53
93
  "impact": "ShaderGUI behavior has no equivalent in the creation specification",
54
94
  })
55
95
  if report["degradations"]:
@@ -78,7 +78,8 @@ def report_template(source: Path, target: Path, version: str, source_raw: bytes)
78
78
  "mapping_version": MAPPING_VERSION,
79
79
  "receiver_schema": {"name": "sgcli.native.v3", "path": None, "sha256": None},
80
80
  "source_validation": {"error_count": 0, "warning_count": 0, "issues": []},
81
- "mappings": [], "dependencies": [], "degradations": [], "diagnostics": [],
81
+ "mappings": [], "dependencies": [], "degradations": [], "presentation_warnings": [],
82
+ "custom_function_manifest": [], "diagnostics": [],
82
83
  "equivalence": {"status": "not_proven", "reason": "effect validation has not run"},
83
84
  "verification": {
84
85
  "source_parse": dict(empty), "source_structure": dict(empty),