@shundoo-ai/dsh-cosmic 1.0.19 → 1.0.21

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 (245) hide show
  1. package/cordis.patch.yml +5 -5
  2. package/package.json +1 -1
  3. package/skills/cosmic-build/CHANGELOG.md +4 -0
  4. package/skills/cosmic-build/LOCAL-PATCHES.md +91 -40
  5. package/skills/cosmic-build/SKILL.md +46 -13
  6. package/skills/cosmic-build/assets/platform-report-filters/TypedReportFilterFields.java +169 -0
  7. package/skills/cosmic-build/assets/platform-report-filters/platform.patch +98 -0
  8. package/skills/cosmic-build/assets/report-algo-benchmark/ReportAlgoBenchmark.java +48 -0
  9. package/skills/cosmic-build/assets/report-algo-benchmark/ReportBenchmarkLogFactory.java +7 -0
  10. package/skills/cosmic-build/examples/java-rules/CosmicEntryQuery.java +26 -0
  11. package/skills/cosmic-build/examples/java-rules/CosmicReportAggregation.java +35 -0
  12. package/skills/cosmic-build/examples/java-rules/CosmicReportFilters.java +77 -0
  13. package/skills/cosmic-build/examples/java-rules/CosmicTimeAdapter.java +25 -0
  14. package/skills/cosmic-build/examples/java-rules/CosmicTimeAdapterCheck.java +26 -0
  15. package/skills/cosmic-build/knowledge/cosmic/platform/api/algo/GroupbyDataSet.md +47 -0
  16. package/skills/cosmic-build/knowledge/cosmic/platform/api/entity/report/FilterInfo.md +12 -12
  17. package/skills/cosmic-build/knowledge/cosmic/platform/api/entity/report/FilterItemInfo.md +2 -0
  18. package/skills/cosmic-build/knowledge/cosmic/platform/form-plugin.md +2 -4
  19. package/skills/cosmic-build/knowledge/cosmic/platform/java-type-contracts.md +11 -2
  20. package/skills/cosmic-build/knowledge/cosmic/platform/list-plugin.md +18 -14
  21. package/skills/cosmic-build/knowledge/cosmic/platform/operation-plugin.md +4 -4
  22. package/skills/cosmic-build/knowledge/cosmic/platform/reportlistdata-plugin.md +17 -9
  23. package/skills/cosmic-build/knowledge/cosmic/platform/scenes/operation/cross-entity-aggregate-writeback.md +2 -0
  24. package/skills/cosmic-build/knowledge/cosmic/platform/scenes/operation/pre-post-operation.md +15 -7
  25. package/skills/cosmic-build/knowledge/cosmic/platform/sdk/sdk-algo.md +24 -68
  26. package/skills/cosmic-build/knowledge/cosmic/platform/workflow-plugin.md +2 -7
  27. package/skills/cosmic-build/references/application-context.md +35 -1
  28. package/skills/cosmic-build/references/common-reference.md +1 -1
  29. package/skills/cosmic-build/references/compile-guide.md +55 -68
  30. package/skills/cosmic-build/references/delivery.md +59 -7
  31. package/skills/cosmic-build/references/execution-contract.md +38 -0
  32. package/skills/cosmic-build/references/form-discovery.md +7 -1
  33. package/skills/cosmic-build/references/java-plugin-delivery.md +32 -162
  34. package/skills/cosmic-build/references/operation-dispatch.md +17 -0
  35. package/skills/cosmic-build/references/plugin-handoff-input.md +131 -0
  36. package/skills/cosmic-build/references/plugin-runtime-routing.md +1 -1
  37. package/skills/cosmic-build/references/report-filter-contract.md +78 -0
  38. package/skills/cosmic-build/references/sdk-inspection.md +23 -0
  39. package/skills/cosmic-build/schemas/data-model-authoring.schema.json +2 -3
  40. package/skills/cosmic-build/scripts/_http_client.py +55 -55
  41. package/skills/cosmic-build/scripts/appconfig_load.py +2 -2
  42. package/skills/cosmic-build/scripts/apply_report_filter_extension.py +39 -0
  43. package/skills/cosmic-build/scripts/bootstrap_cosmic_context.py +37 -2
  44. package/skills/cosmic-build/scripts/compile_plugin_source.py +279 -156
  45. package/skills/cosmic-build/scripts/execution_binding.py +40 -0
  46. package/skills/cosmic-build/scripts/inspect_platform_sdk.py +169 -0
  47. package/skills/cosmic-build/scripts/kd_api.py +23 -22
  48. package/skills/cosmic-build/scripts/kd_auth.py +1 -1
  49. package/skills/cosmic-build/scripts/kd_env_loader.py +19 -10
  50. package/skills/cosmic-build/scripts/kd_token_cache.py +2 -2
  51. package/skills/cosmic-build/scripts/kingscript_sdk_sync.py +350 -0
  52. package/skills/cosmic-build/scripts/kingscript_source_gate.py +11 -8
  53. package/skills/cosmic-build/scripts/platform_api_contract.py +246 -11
  54. package/skills/cosmic-build/scripts/plugin_corpus/build_index.py +403 -0
  55. package/skills/cosmic-build/scripts/plugin_corpus/jvm_classfile.py +281 -0
  56. package/skills/cosmic-build/scripts/plugin_corpus/measure_api_usage.py +446 -0
  57. package/skills/cosmic-build/scripts/plugin_source_gate.py +48 -7
  58. package/skills/cosmic-build/scripts/plugin_target_sdk.py +45 -0
  59. package/skills/cosmic-build/scripts/prepare_plugin_handoff.py +493 -47
  60. package/skills/cosmic-build/scripts/preview_url.py +35 -6
  61. package/skills/cosmic-build/scripts/query_plugin_handoff.py +250 -0
  62. package/skills/cosmic-build/scripts/register_plugins.py +28 -2
  63. package/skills/cosmic-build/scripts/render_output_cards.py +42 -9
  64. package/skills/cosmic-build/scripts/report_algo_benchmark.py +46 -0
  65. package/skills/cosmic-build/scripts/run.py +2 -2
  66. package/skills/cosmic-build/scripts/sync_generated_locale_assets.py +43 -0
  67. package/skills/cosmic-build/scripts/test/fixtures/ReportSdkCheck.java +64 -0
  68. package/skills/cosmic-build/scripts/test/fixtures/java_context_booking_native.json +541 -0
  69. package/skills/cosmic-build/scripts/test/test_add_rule_business_contract.py +85 -14
  70. package/skills/cosmic-build/scripts/test/test_batch5_drift_governance.py +12 -3
  71. package/skills/cosmic-build/scripts/test/test_build_meta_order.py +0 -16
  72. package/skills/cosmic-build/scripts/test/test_cli_continuation.py +87 -0
  73. package/skills/cosmic-build/scripts/test/test_compile_plugin_source.py +224 -3
  74. package/skills/cosmic-build/scripts/test/test_control_authoring.py +123 -4
  75. package/skills/cosmic-build/scripts/test/test_cosmic_sdk_examples.py +141 -0
  76. package/skills/cosmic-build/scripts/test/test_data_model_contract.py +30 -5
  77. package/skills/cosmic-build/scripts/test/test_delivery_stage_boundary.py +2 -10
  78. package/skills/cosmic-build/scripts/test/test_dym_sync_background.py +11 -0
  79. package/skills/cosmic-build/scripts/test/test_dynamic_form_metadata_only_contract.py +59 -1
  80. package/skills/cosmic-build/scripts/test/test_guide_skeleton_contract.py +87 -43
  81. package/skills/cosmic-build/scripts/test/test_inspect_platform_sdk.py +71 -0
  82. package/skills/cosmic-build/scripts/test/test_kd_api.py +67 -19
  83. package/skills/cosmic-build/scripts/test/test_kingscript_sdk_sync.py +221 -0
  84. package/skills/cosmic-build/scripts/test/test_kingscript_source_gate.py +10 -0
  85. package/skills/cosmic-build/scripts/test/test_list_configuration_closure.py +18 -0
  86. package/skills/cosmic-build/scripts/test/test_long_session_regressions.py +116 -0
  87. package/skills/cosmic-build/scripts/test/test_mcp_cli.py +524 -0
  88. package/skills/cosmic-build/scripts/test/test_modeling_input_recovery.py +141 -0
  89. package/skills/cosmic-build/scripts/test/test_open_world_cli_catalog.py +36 -2
  90. package/skills/cosmic-build/scripts/test/test_platform_api_contract.py +161 -1
  91. package/skills/cosmic-build/scripts/test/test_plugin_business_contract.py +91 -0
  92. package/skills/cosmic-build/scripts/test/test_plugin_corpus.py +195 -0
  93. package/skills/cosmic-build/scripts/test/test_plugin_handoff.py +346 -1
  94. package/skills/cosmic-build/scripts/test/test_plugin_target_sdk.py +70 -0
  95. package/skills/cosmic-build/scripts/test/test_preview_url.py +44 -1
  96. package/skills/cosmic-build/scripts/test/test_property_batch.py +22 -0
  97. package/skills/cosmic-build/scripts/test/test_property_input_discovery.py +13 -11
  98. package/skills/cosmic-build/scripts/test/test_query_plugin_handoff.py +160 -0
  99. package/skills/cosmic-build/scripts/test/test_register_plugins.py +31 -1
  100. package/skills/cosmic-build/scripts/test/test_render_output_cards.py +50 -4
  101. package/skills/cosmic-build/scripts/test/test_report_business_contract.py +27 -0
  102. package/skills/cosmic-build/scripts/test/test_report_doc_contract_sync.py +5 -4
  103. package/skills/cosmic-build/scripts/test/test_report_sdk_optimization.py +36 -0
  104. package/skills/cosmic-build/scripts/test/test_rule_batch_evidence.py +1 -1
  105. package/skills/cosmic-build/scripts/test/test_rule_domain_contract.py +20 -0
  106. package/skills/cosmic-build/scripts/test/test_rule_function_formula.py +16 -6
  107. package/skills/cosmic-build/scripts/test/test_skill_entry_contract.py +1 -0
  108. package/skills/cosmic-build/scripts/test/test_test_environment.py +45 -0
  109. package/skills/cosmic-build/scripts/test/test_verify_plugin_loading.py +79 -0
  110. package/skills/cosmic-build/scripts/test_environment.py +49 -0
  111. package/skills/cosmic-build/scripts/verify_plugin_loading.py +71 -0
  112. package/skills/cosmic-build/skills/cosmic-coding-impl/SKILL.md +86 -162
  113. package/skills/cosmic-build/skills/cosmic-coding-script/ATTRIBUTION.md +1 -1
  114. package/skills/cosmic-build/skills/cosmic-coding-script/SKILL.md +45 -14
  115. package/skills/cosmic-build/skills/cosmic-coding-script/references/kwc-controller-authoring.md +6 -0
  116. package/skills/cosmic-build/skills/cosmic-coding-script/references/sdk/README.md +29 -19
  117. package/skills/cosmic-build/skills/cosmic-coding-script/references/sdk/docs//350/204/232/346/234/254SDK.md +3 -4
  118. package/skills/cosmic-build/skills/cosmic-coding-script/references/sdk/indexes/package-index.md +1 -1
  119. package/skills/cosmic-build/skills/cosmic-coding-script/references/sdk/strategy.md +27 -18
  120. package/skills/cosmic-build/skills/cosmic-meta-api/SKILL.md +11 -17
  121. package/skills/cosmic-build/skills/cosmic-meta-api/apis/ai_meta.md +1 -1
  122. package/skills/cosmic-build/skills/cosmic-meta-api/apis/app_menu.md +1 -1
  123. package/skills/cosmic-build/skills/cosmic-meta-api/apis/meta_log.md +1 -1
  124. package/skills/cosmic-build/skills/cosmic-meta-api/contracts/cli/control-authoring.json +45 -4
  125. package/skills/cosmic-build/skills/cosmic-meta-api/contracts/cli/form-control-traits.json +1 -1
  126. package/skills/cosmic-build/skills/cosmic-meta-api/contracts/cli/layout-ui.json +18 -0
  127. package/skills/cosmic-build/skills/cosmic-meta-api/contracts/cli/menu-publish.json +8 -2
  128. package/skills/cosmic-build/skills/cosmic-meta-api/contracts/cli/property-batch.json +7 -0
  129. package/skills/cosmic-build/skills/cosmic-meta-api/contracts/cli/property-input-index.json +3 -3
  130. package/skills/cosmic-build/skills/cosmic-meta-api/contracts/cli/report-write-contracts.json +1 -0
  131. package/skills/cosmic-build/skills/cosmic-meta-api/contracts/cli/rule-domain.json +37 -5
  132. package/skills/cosmic-build/skills/cosmic-meta-api/contracts/cli/rule-event-contract.json +24 -3
  133. package/skills/cosmic-build/skills/cosmic-meta-api/contracts/cli/run-build-meta.json +61 -12
  134. package/skills/cosmic-build/skills/cosmic-meta-api/contracts/schema/dropdown-menu.schema.json +69 -0
  135. package/skills/cosmic-build/skills/cosmic-meta-api/contracts/schema/report-write.schema.json +2 -1
  136. package/skills/cosmic-build/skills/cosmic-meta-api/contracts/schema/rule-set.schema.json +1 -0
  137. package/skills/cosmic-build/skills/cosmic-meta-api/contracts/schema/rule-write.schema.json +14 -7
  138. package/skills/cosmic-build/skills/cosmic-meta-api/docs/api-summary.md +2 -2
  139. package/skills/cosmic-build/skills/cosmic-meta-api/modules/app-action/SKILL.md +6 -3
  140. package/skills/cosmic-build/skills/cosmic-meta-api/modules/develop/SKILL.md +1 -2
  141. package/skills/cosmic-build/skills/cosmic-meta-api/modules/export/SKILL.md +5 -6
  142. package/skills/cosmic-build/skills/cosmic-meta-api/modules/init/SKILL.md +13 -36
  143. package/skills/cosmic-build/skills/cosmic-meta-api/modules/pdm/SKILL.md +8 -9
  144. package/skills/cosmic-build/skills/cosmic-meta-api/modules/pdm/scripts/config.json.example +5 -15
  145. package/skills/cosmic-build/skills/cosmic-meta-api/modules/reset/SKILL.md +6 -6
  146. package/skills/cosmic-build/skills/cosmic-meta-api/modules/usage/SKILL.md +20 -148
  147. package/skills/cosmic-build/skills/cosmic-meta-api/modules/verify/SKILL.md +1 -1
  148. package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/build_receipts.py +171 -0
  149. package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/cmd_apps.py +25 -6
  150. package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/cmd_controls.py +55 -21
  151. package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/cmd_fields.py +10 -3
  152. package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/cmd_formactions.py +63 -6
  153. package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/cmd_forms.py +59 -2
  154. package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/cmd_listui.py +8 -0
  155. package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/cmd_metaops.py +36 -1
  156. package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/cmd_plugins.py +115 -90
  157. package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/cmd_properties.py +666 -4
  158. package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/cmd_rules.py +1415 -87
  159. package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/commands.py +6 -1
  160. package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/config.py +28 -15
  161. package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/execution_errors.py +40 -0
  162. package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/formatters.py +32 -5
  163. package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/property_policy_contract.py +6 -0
  164. package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/report_ops.py +113 -17
  165. package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/reset.py +3 -3
  166. package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/rule_contract.py +107 -26
  167. package/skills/cosmic-build/skills/cosmic-meta-api/scripts/build_meta_order.py +50 -49
  168. package/skills/cosmic-build/skills/cosmic-meta-api/scripts/cosmic_api.py +856 -150
  169. package/skills/cosmic-build/skills/cosmic-meta-api/scripts/field_decorator.py +47 -14
  170. package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_build_receipt_resume.py +374 -0
  171. package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_cli_failure_contract.py +24 -0
  172. package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_creation_identity_boundary.py +4 -2
  173. package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_dropdown_menu_contract.py +382 -0
  174. package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_existing_form_ui.py +0 -25
  175. package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_field_decorator.py +50 -6
  176. package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_functional_group_resolution.py +83 -16
  177. package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_identity_template_resolution.py +103 -0
  178. package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_report_plugin_contract.py +28 -2
  179. package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_report_readback_derivation.py +22 -0
  180. package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_report_typed_filters.py +65 -0
  181. package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_rule_write_closure.py +1041 -15
  182. package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_run_batch_post_build_recovery.py +65 -0
  183. package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_run_batch_verification_evidence.py +17 -0
  184. package/skills/cosmic-build/skills/cosmic-meta-knowledge/generation/api-param-checklist.md +1 -1
  185. package/skills/cosmic-build/skills/cosmic-meta-knowledge/generation/rule-modeling-guide.md +7 -4
  186. package/skills/cosmic-build/skills/cosmic-meta-modeling/SKILL.md +61 -13
  187. package/skills/cosmic-build/skills/cosmic-meta-modeling/modules/app-menu/SKILL.md +8 -0
  188. package/skills/cosmic-build/skills/cosmic-meta-modeling/modules/formtemplate/SKILL.md +5 -0
  189. package/skills/cosmic-build/skills/cosmic-meta-modeling/modules/formtemplate/dynamic-form-artifact-schema.md +5 -0
  190. package/skills/cosmic-build/skills/cosmic-meta-modeling/modules/report/SKILL.md +21 -9
  191. package/skills/cosmic-build/skills/cosmic-meta-modeling/references/authoring-entity-graphs.md +1 -1
  192. package/skills/cosmic-build/skills/cosmic-meta-modeling/references/authoring-storage-constraints.md +5 -3
  193. package/skills/cosmic-build/skills/cosmic-meta-modeling/references/authoring-ui-composition.md +6 -3
  194. package/skills/cosmic-build/skills/cosmic-meta-modeling/references/creation-recovery.md +13 -0
  195. package/skills/cosmic-build/skills/cosmic-meta-modeling/references/parse-core.md +3 -0
  196. package/skills/cosmic-build/skills/cosmic-meta-modeling/scripts/data_model_contract.py +6 -1
  197. package/skills/cosmic-build/skills/cosmic-meta-modeling/scripts/data_model_emit.py +135 -87
  198. package/skills/cosmic-build/skills/cosmic-meta-modeling/scripts/field_type_registry.py +11 -1
  199. package/skills/cosmic-build/skills/cosmic-meta-modeling/scripts/isv_resolver.py +1 -3
  200. package/skills/cosmic-build/skills/cosmic-meta-modeling/scripts/report_validator.py +29 -0
  201. package/skills/cosmic-build/skills/cosmic-meta-modifier/SKILL.md +4 -2
  202. package/skills/cosmic-build/skills/cosmic-meta-modifier/modules/context/SKILL.md +2 -2
  203. package/skills/cosmic-build/skills/cosmic-meta-modifier/modules/execute/SKILL.md +1 -1
  204. package/skills/cosmic-build/skills/cosmic-meta-modifier/modules/operation/SKILL.md +5 -4
  205. package/skills/cosmic-build/skills/cosmic-meta-modifier/modules/operation/operation-write.md +6 -2
  206. package/skills/cosmic-build/skills/cosmic-meta-modifier/modules/operation/validation.md +2 -0
  207. package/skills/cosmic-build/skills/cosmic-meta-modifier/modules/property/SKILL.md +20 -5
  208. package/skills/cosmic-build/skills/cosmic-meta-modifier/modules/property/complex-apis.md +1 -1
  209. package/skills/cosmic-build/skills/cosmic-meta-modifier/modules/property/policy-grammar.md +4 -1
  210. package/skills/cosmic-build/skills/cosmic-meta-modifier/modules/report-op/SKILL.md +9 -0
  211. package/skills/cosmic-build/skills/cosmic-meta-modifier/modules/rule/SKILL.md +61 -4
  212. package/skills/cosmic-build/skills/cosmic-meta-modifier/modules/rule/raw-rule-authoring.md +3 -1
  213. package/skills/cosmic-build/skills/cosmic-meta-modifier/modules/rule/rule-actions.md +2 -2
  214. package/skills/cosmic-build/skills/cosmic-meta-modifier/modules/rule/rule-reference.md +6 -6
  215. package/skills/cosmic-build/skills/cosmic-meta-modifier/modules/rule/state.md +1 -1
  216. package/skills/cosmic-build/skills/cosmic-meta-modifier/modules/unit/SKILL.md +6 -3
  217. package/skills/cosmic-build/skills/cosmic-meta-modifier/modules/verify/usage-guide.md +4 -4
  218. package/skills/cosmic-build/skills/cosmic-meta-modifier/references/list-filter-modification.md +4 -1
  219. package/skills/cosmic-build/skills/cosmic-meta-ui/SKILL.md +9 -1
  220. package/skills/cosmic-build/skills/cosmic-meta-ui/modules/button/SKILL.md +3 -0
  221. package/skills/cosmic-build/skills/mcp-server/SKILL.md +210 -0
  222. package/skills/cosmic-build/skills/mcp-server/scripts/mcp_cli.py +431 -0
  223. package/skills/cosmic-build/skills/openapi-gen/SKILL.md +3 -3
  224. package/skills/cosmic-build/skills/openapi-gen/scripts/api/gen_runner.py +2 -2
  225. package/skills/cosmic-dev-best-practices/references/bill-dev-convention.md +19 -9
  226. package/skills/cosmic-dev-best-practices/references/cosmic-meta-api.md +14 -11
  227. package/skills/cosmic-dev-best-practices/references/design-examples/basedata-design-example.md +1 -1
  228. package/skills/cosmic-dev-best-practices/references/design-examples/bill-design-example.md +1 -1
  229. package/skills/cosmic-dev-best-practices/references/elements/AssistantField.md +1 -1
  230. package/skills/cosmic-dev-best-practices/references/elements/BasedataField.md +2 -2
  231. package/skills/cosmic-dev-best-practices/references/elements/BasedataPropField.md +3 -3
  232. package/skills/cosmic-dev-best-practices/references/elements/CreaterField.md +2 -2
  233. package/skills/cosmic-dev-best-practices/references/elements/CurrencyField.md +2 -2
  234. package/skills/cosmic-dev-best-practices/references/elements/CustomerField.md +2 -2
  235. package/skills/cosmic-dev-best-practices/references/elements/FlexField.md +1 -1
  236. package/skills/cosmic-dev-best-practices/references/elements/MaterielField.md +2 -2
  237. package/skills/cosmic-dev-best-practices/references/elements/OrgField.md +2 -2
  238. package/skills/cosmic-dev-best-practices/references/elements/SupplierField.md +2 -2
  239. package/skills/cosmic-dev-best-practices/references/elements/UnitField.md +1 -1
  240. package/skills/cosmic-dev-best-practices/references/elements/UserField.md +3 -3
  241. package/skills/cosmic-dev-best-practices/references/elements/common-field-property-conventions.md +16 -11
  242. package/skills/cosmic-dev-best-practices/references/layout-control-convention.md +5 -4
  243. package/skills/erp-analysis/references/delivery-contract.md +4 -2
  244. package/skills/erp-analysis/templates/AGENTS.template.md +1 -1
  245. package/skills/cosmic-build/skills/cosmic-meta-api/scripts/.dsh/cosmic/.kd/config.json +0 -21
@@ -1,5 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import argparse
3
4
  import importlib
4
5
  import json
5
6
  import sys
@@ -225,7 +226,7 @@ class AddRuleBusinessContractTest(unittest.TestCase):
225
226
  mismatches = cosmic_api._rule_readback_mismatches(expected, observed, metadata)
226
227
  self.assertTrue(any(item["path"].endswith(".Fields") for item in mismatches))
227
228
 
228
- def test_form_rule_rejects_unknown_and_unsupported_ret_bits(self) -> None:
229
+ def test_rule_ret_accepts_designer_after_copy_and_rejects_unknown_bits(self) -> None:
229
230
  with self.assertRaisesRegex(ValueError, "RULE_RET_UNKNOWN_EVENT_BIT"):
230
231
  rule_contract.normalize_rule_config(
231
232
  {
@@ -239,19 +240,89 @@ class AddRuleBusinessContractTest(unittest.TestCase):
239
240
  ],
240
241
  }
241
242
  )
242
- with self.assertRaisesRegex(ValueError, "RULE_RET_UNSUPPORTED"):
243
- rule_contract.normalize_rule_config(
244
- {
245
- "ruleType": "formRule",
246
- "trueActions": [
247
- {
248
- "actionType": "HideFieldAction",
249
- "fields": ["field_b"],
250
- "RET": 4,
251
- }
252
- ],
253
- }
254
- )
243
+ for action_type, original in rule_contract._EVENT_CONTRACT["actionMasks"].items():
244
+ with self.subTest(action=action_type):
245
+ for bit in rule_contract._EVENT_CONTRACT["eventBits"]:
246
+ rule_contract.validate_action_ret(action_type, int(bit))
247
+ rule_contract.validate_action_ret(action_type, 2047)
248
+ merged = rule_contract.merge_action_events(
249
+ action_type, original, ["复制后"],
250
+ )
251
+ self.assertEqual(original | 1024, merged)
252
+ self.assertEqual(merged, rule_contract.merge_action_events(
253
+ action_type, merged, ["AfterCopy"],
254
+ ))
255
+ for action_type, rule_type, target_args, ret in (
256
+ ("HideFieldAction", "formRule", {"fields": ["field_b"]}, 1275),
257
+ ("CallFieldChangeAction", "bizRule", {"expression": "field_b"}, 1797),
258
+ ):
259
+ result = rule_contract.normalize_rule_config({
260
+ "ruleType": rule_type,
261
+ "trueActions": [{"actionType": action_type, "ret": ret, **target_args}],
262
+ })
263
+ self.assertEqual(ret, result["trueActions"][0]["RET"])
264
+ with self.assertRaisesRegex(ValueError, "RULE_ACTION_CONTRACT_BLOCKED"):
265
+ rule_contract.validate_action_ret("SetVisibleAction", 1024)
266
+ for invalid in (True, "1024", 0, -1):
267
+ with self.subTest(invalid=invalid):
268
+ with self.assertRaisesRegex(ValueError, "RULE_RET_INVALID"):
269
+ rule_contract.validate_action_ret("ClearValueAction", invalid)
270
+ business = rule_contract.normalize_rule_config({
271
+ "ruleType": "bizRule",
272
+ "trueActions": [{
273
+ "actionType": "ClearValueAction", "expression": "field_b",
274
+ "RET": 1021 | 1024,
275
+ }],
276
+ })
277
+ self.assertEqual(2045, business["trueActions"][0]["RET"])
278
+ self.assertEqual(2045, rule_contract.merge_action_events(
279
+ "ClearValueAction", 1021, ["复制后", "AfterCopy"],
280
+ ))
281
+ self.assertEqual(1025, rule_contract.select_action_events(
282
+ "CallFieldChangeAction", ["字段值变化", "复制后"],
283
+ ))
284
+ self.assertEqual(1027, rule_contract.select_action_events(
285
+ "HideFieldAction", ["加载", "字段值变化", "复制后"],
286
+ ))
287
+ self.assertEqual(1021, rule_contract.merge_action_events(
288
+ "ClearValueAction", 253,
289
+ ["新建", "字段值变化", "创建后", "字段值变化后"],
290
+ ))
291
+ self.assertEqual(1021, rule_contract.merge_action_events(
292
+ "ClearValueAction", 253,
293
+ ["Create", "FieldChange", "AfterCreate", "AfterFieldChange"],
294
+ ))
295
+ with self.assertRaisesRegex(ValueError, "RULE_EVENT_UNKNOWN"):
296
+ rule_contract.merge_action_events("ClearValueAction", 253, ["typo"])
297
+ with self.assertRaisesRegex(ValueError, "RULE_EVENTS_INVALID"):
298
+ rule_contract.merge_action_events("ClearValueAction", 253, "AfterCopy")
299
+
300
+ def test_clear_fields_cli_retains_every_repeated_target(self) -> None:
301
+ class Parsed(Exception):
302
+ def __init__(self, value):
303
+ self.value = value
304
+
305
+ original = argparse.ArgumentParser.parse_args
306
+
307
+ def capture(parser, _args=None, namespace=None):
308
+ return_value = original(parser, arguments, namespace)
309
+ raise Parsed(return_value)
310
+
311
+ prefix = [
312
+ "ensureConditionalClearFields", "--formNumber", "demo",
313
+ "--condition-field", "数量", "--operator", "greater-than", "--value", "10",
314
+ ]
315
+ for suffix in (
316
+ ["--target", "单价", "--target", "备注"],
317
+ ["--target", "单价", "备注"],
318
+ ):
319
+ arguments = prefix + suffix + ["--add-event", "新建"]
320
+ with self.subTest(suffix=suffix):
321
+ with mock.patch.object(cosmic_api._CliArgumentParser, "parse_args", capture):
322
+ with self.assertRaises(Parsed) as result:
323
+ cosmic_api._main_impl()
324
+ self.assertEqual(["单价", "备注"], result.exception.value.targets)
325
+ self.assertEqual(["新建"], result.exception.value.add_events)
255
326
 
256
327
  def test_direct_rule_enables_trigger_field_event_before_write(self) -> None:
257
328
  rule = {"triggerField": "字段A(uhyl_field_a);uhyl_field_c"}
@@ -34,14 +34,23 @@ class GeneratedLocaleAssetsTest(unittest.TestCase):
34
34
  result = module.inspect()
35
35
  self.assertTrue(result["ok"], result)
36
36
  self.assertEqual(
37
- {"control-authoring-v1", "data-model-compiler-v1", "entry-write-v1", "existing-form-ui-v1",
37
+ {"control-authoring-v1", "data-model-compiler-v1", "dym-sync-contract-v2",
38
+ "entry-write-v1", "existing-form-ui-v1",
39
+ "kingscript-gate-v1", "mcp-server-v1", "metalog-v1",
38
40
  "operation-contract-harvest-v1", "operation-write-v1",
39
- "plugin-handoff-v1", "kingscript-gate-v1",
40
- "report-tests-v1", "report-write-v1", "rule-write-v1"},
41
+ "plugin-handoff-v1", "property-policy-contract-v1", "python-runtime-v1",
42
+ "report-tests-v1", "report-write-v1", "rule-write-v1", "execution-recovery-v1", "plugin-handoff-query-v1"},
41
43
  set(result["families"]),
42
44
  )
43
45
  self.assertEqual(len(result["files"]), result["counts"]["in_sync"])
44
46
 
47
+ def test_execution_recovery_mirrors_are_machine_synced(self) -> None:
48
+ module = _load_sync_module()
49
+ result = module.inspect(["execution-recovery-v1"])
50
+ self.assertTrue(result["ok"], result)
51
+ self.assertIn("skills/cosmic-meta-api/scripts/_core/build_receipts.py",
52
+ module.GENERATED_FAMILIES["execution-recovery-v1"])
53
+
45
54
  def test_report_test_mirrors_are_machine_synced_not_hand_maintained(self) -> None:
46
55
  """Of the 37 test mirrors that predate this family, 32 had drifted.
47
56
 
@@ -23,7 +23,6 @@ from build_meta_order import ( # noqa: E402
23
23
  BuildDependencyError,
24
24
  bind_ref_bill_ids,
25
25
  collect_ref_bill_targets,
26
- dependency_blocked_results,
27
26
  plan_build_waves,
28
27
  split_deferred_ref_bill_writes,
29
28
  split_deferred_property_fields,
@@ -461,21 +460,6 @@ class TestBuildMetaOrder(unittest.TestCase):
461
460
  set(map(os.path.abspath, paths)),
462
461
  )
463
462
 
464
- def test_failed_wave_blocks_all_later_writes(self):
465
- waves = [
466
- ["/tmp/product.json", "/tmp/member.json"],
467
- ["/tmp/order.json"],
468
- ["/tmp/order_rules.json"],
469
- ]
470
- blocked = dependency_blocked_results(waves, failed_wave_index=1)
471
- self.assertEqual(
472
- [item["artifact"] for item in blocked],
473
- ["order.json", "order_rules.json"],
474
- )
475
- self.assertTrue(
476
- all(item["errorCode"] == "DEPENDENCY_WAVE_FAILED" for item in blocked)
477
- )
478
- self.assertTrue(all(item["phase"] == "dependency" for item in blocked))
479
463
 
480
464
 
481
465
  if __name__ == "__main__":
@@ -0,0 +1,87 @@
1
+ import json
2
+ import subprocess
3
+ import sys
4
+ from pathlib import Path
5
+
6
+ ROOT = Path(__file__).resolve().parents[2]
7
+ MODELING = ROOT / "skills/cosmic-meta-modeling/scripts"
8
+
9
+
10
+ def run(script, *args):
11
+ return subprocess.run([sys.executable, str(script), *args], capture_output=True, text=True)
12
+
13
+
14
+ def test_compiler_describes_the_existing_schema_without_workspace_or_platform(tmp_path):
15
+ result = run(MODELING / "data_model_emit.py", "--describe")
16
+ assert result.returncode == 0, result.stderr
17
+ contract = json.loads(result.stdout)
18
+ assert contract["inputSchema"] == json.loads((ROOT / "schemas/data-model-authoring.schema.json").read_text())
19
+ assert {arg["flags"][0] for arg in contract["arguments"] if arg["required"]} == {"--app-root", "--authoring-file"}
20
+ assert contract["execution"]["argvPrefix"][1] == str(MODELING / "data_model_emit.py")
21
+ localized = run(ROOT / ".locales/zh/skills/cosmic-meta-modeling/scripts/data_model_emit.py", "--describe")
22
+ assert localized.returncode == 0, localized.stderr
23
+ assert json.loads(localized.stdout)["inputSchema"] == contract["inputSchema"]
24
+ authoring = contract["authoringContract"]
25
+ assert json.loads(localized.stdout)["authoringContract"] == {
26
+ **authoring,
27
+ "templateFieldInspection": {
28
+ **authoring["templateFieldInspection"],
29
+ "argv": [sys.executable, str(ROOT / ".locales/zh/skills/cosmic-meta-api/scripts/cosmic_api.py"),
30
+ *authoring["templateFieldInspection"]["argv"][2:]],
31
+ },
32
+ }
33
+ assert authoring["callerFieldInputs"] == contract["inputSchema"]["definitions"]["field"]["required"]
34
+ sys.path.insert(0, str(MODELING))
35
+ from data_model_emit import _apply_direct_authoring_constraints
36
+ for kind, template in authoring["defaultTemplates"].items():
37
+ section = {"artifact": {"entities": [{"type": kind, "fields": []}]}}
38
+ _apply_direct_authoring_constraints(section)
39
+ assert section["artifact"]["entities"][0]["templateKey"] == template
40
+ selected = {"artifact": {"entities": [{"type": kind, "templateKey": "explicit_template", "fields": []}]}}
41
+ _apply_direct_authoring_constraints(selected)
42
+ assert selected["artifact"]["entities"][0]["templateKey"] == "explicit_template"
43
+ inspection = authoring["templateFieldInspection"]["argv"]
44
+ help_result = run(Path(inspection[1]), "--stdout", "getEntityFields", "--help")
45
+ assert help_result.returncode == 0, help_result.stderr
46
+ assert all(flag in help_result.stdout for flag in ("--app-root", "--formNumber"))
47
+ assert not list(tmp_path.iterdir())
48
+
49
+
50
+ def test_catalog_queries_reuse_source_and_unknown_types_fail():
51
+ script = MODELING / "field_type_registry.py"
52
+ full = json.loads(run(script, "--catalog").stdout)
53
+ selected = json.loads(run(script, "--catalog", "--types", "DateField", "BasedataField", "TextField").stdout)
54
+ assert selected["fieldTypes"] == [x for x in full["fieldTypes"] if x["name"] in {"DateField", "BasedataField", "TextField"}]
55
+ compact = json.loads(run(script, "--catalog", "--compact").stdout)
56
+ assert [(x["name"], x["semantics"]) for x in compact["fieldTypes"]] == [(x["name"], x["semantics"]) for x in full["fieldTypes"]]
57
+ assert len(json.dumps(compact)) < len(json.dumps(full))
58
+ assert run(script, "--catalog", "--types", "InventedField").returncode != 0
59
+
60
+
61
+ def test_saved_receipt_exposes_next_command_without_inventing_verification(tmp_path, capsys):
62
+ api_scripts = ROOT / "skills/cosmic-meta-api/scripts"
63
+ sys.path.insert(0, str(api_scripts))
64
+ from _core import formatters
65
+
66
+ output = tmp_path / "receipt.json"
67
+ receipt = {"success": 1, "failed": 1, "results": [
68
+ {"ok": True, "phase": "buildMeta", "verification": {"status": "pass"}},
69
+ {"ok": False, "phase": "unknown", "error": "response lost"},
70
+ ], "delivery": {"command": ["python", "render.py", "--form-number", "verified-target"]},
71
+ "doNotRetryBuildMeta": True, "reconcile": {"ready": True}}
72
+ formatters.set_output_file(str(output))
73
+ formatters.set_stdout_mode(False)
74
+ try:
75
+ formatters.pjson(receipt)
76
+ summary = json.loads(capsys.readouterr().out.split("RESULT_SUMMARY=", 1)[1])
77
+ assert json.loads(output.read_text()) == receipt
78
+ assert summary["delivery"] == receipt["delivery"]
79
+ assert summary["doNotRetryBuildMeta"] is True
80
+ assert summary["results"][0]["verification"] == {"status": "pass"}
81
+ assert "verification" not in summary["results"][1]
82
+ formatters.set_stdout_mode(True)
83
+ formatters.pjson(receipt)
84
+ assert json.loads(capsys.readouterr().out) == receipt
85
+ finally:
86
+ formatters.set_stdout_mode(False)
87
+ formatters.set_output_file(None)
@@ -1,4 +1,6 @@
1
1
  import json
2
+ import os
3
+ import subprocess
2
4
  import sys
3
5
  from pathlib import Path
4
6
  from types import SimpleNamespace
@@ -23,6 +25,29 @@ def test_resolve_module_uses_project_dir_mapping(tmp_path):
23
25
  assert resolve_module(gradle_root, module_root) == ":demo"
24
26
 
25
27
 
28
+ def test_compile_environment_reports_only_configured_sdk_libraries(tmp_path, monkeypatch):
29
+ gradle = tmp_path / "gradle"
30
+ project = gradle / "code" / "demo"
31
+ project.mkdir(parents=True)
32
+ (gradle / "settings.gradle").write_text("include(':demo')\nproject(':demo').projectDir = new File('code/demo')\n")
33
+ sdk = tmp_path / "target-sdk"
34
+ bos = sdk / "mservice-cosmic" / "lib" / "bos"
35
+ bos.mkdir(parents=True)
36
+ (bos / "target.jar").write_bytes(b"")
37
+ (sdk / "mservice" / "lib" / "bos").mkdir(parents=True)
38
+ (sdk / "mservice" / "lib" / "bos" / "other.jar").write_bytes(b"")
39
+ (gradle / "gradle.properties").write_text(f"systemProp.cosmic_home={sdk}\nsecret.password=not-read\n")
40
+ (gradle / "config.gradle").write_text('cosmic_libs_path = "${cosmic_home}/mservice-cosmic/lib"\npath = [bos : "${cosmic_libs_path}/bos"]\n')
41
+ monkeypatch.setattr(compile_plugin_source, "inspect_config", lambda write_derived: {
42
+ "status": "ready", "GRADLE_ROOT": str(gradle), "JAVA_HOME": str(tmp_path / "jdk")})
43
+ result = compile_plugin_source.inspect_compile_environment(str(project))
44
+ assert result["status"] == "ready" and result["module"] == ":demo"
45
+ assert [item["path"] for item in result["sdkDirectories"]] == [str(bos.resolve())]
46
+ assert "not-read" not in str(result)
47
+ assert result["sdkDirectories"][0]["source"] == [str((gradle / "gradle.properties").resolve()),
48
+ str((gradle / "config.gradle").resolve())]
49
+
50
+
26
51
  def test_validate_source_blocks_unresolved_dependency_markers(tmp_path):
27
52
  project_root = tmp_path / "module"
28
53
  source = project_root / "src" / "main" / "java" / "demo" / "Task.java"
@@ -39,9 +64,76 @@ def test_validate_source_blocks_unresolved_dependency_markers(tmp_path):
39
64
  assert issues == [{"line": 1, "message": "unresolved L3 dependency"}]
40
65
 
41
66
 
67
+ def test_timeprop_hints_survive_single_and_batch_handoff_without_false_blocking(tmp_path):
68
+ project_root = tmp_path / "module"
69
+ source = project_root / "src" / "main" / "java" / "demo" / "Booking.java"
70
+ source.parent.mkdir(parents=True)
71
+ source.write_text(
72
+ 'class Booking {\n'
73
+ ' private static final String START = "start_time";\n'
74
+ ' void check(DynamicObject row) { row.getDate(START); }\n'
75
+ '}\n', encoding="utf-8",
76
+ )
77
+ handoff = project_root / "app" / "_runtime" / "Booking.json"
78
+ handoff.parent.mkdir(parents=True)
79
+ handoff.write_text(json.dumps({"status": True, "handoff": {
80
+ "projectRoot": str(project_root), "appRoot": str(project_root / "app"),
81
+ "sourcePath": str(source), "className": "Booking", "type": "operation",
82
+ "formNumber": "booking", "description": "时段检查", "operationKeys": ["save"],
83
+ "formGraph": {"entities": [{"fields": [{"fieldKey": "start_time", "fieldType": "TimeProp"}]}]},
84
+ }}), encoding="utf-8")
85
+ config = tmp_path / "appconfig.json"
86
+ config.write_text('{"compile": false}')
87
+ env = {**os.environ, "KD_APPCONFIG": str(config)}
88
+ run = subprocess.run([sys.executable, str(SCRIPTS / "compile_plugin_source.py"),
89
+ "--handoff", str(handoff)], capture_output=True, text=True, env=env)
90
+ outcome = json.loads(run.stdout)
91
+ assert run.returncode == 0
92
+ assert outcome["compileSkipped"] is True
93
+ assert outcome["compiledArtifact"] is None
94
+ assert outcome["loadingVerification"]["runtimeVerified"] is False
95
+ assert outcome["fieldAccessorCheck"] == "metadata-hints"
96
+ assert outcome["sourceWarnings"][0]["fieldKeys"] == ["start_time"]
97
+ batch = tmp_path / "sources.json"
98
+ batch.write_text(json.dumps([{"handoffPath": str(handoff)}]))
99
+ run = subprocess.run([sys.executable, str(SCRIPTS / "compile_plugin_source.py"),
100
+ "--project-root", str(project_root), "--app-root", str(project_root / "app"),
101
+ "--sources-file", str(batch)], capture_output=True, text=True, env=env)
102
+ result = json.loads(run.stdout)
103
+ assert run.returncode == 0
104
+ assert result["results"][0]["sourceWarnings"] == outcome["sourceWarnings"]
105
+ run = subprocess.run([sys.executable, str(SCRIPTS / "compile_plugin_source.py"),
106
+ "--project-root", str(project_root), "--app-root", str(tmp_path / "another-app"),
107
+ "--sources-file", str(batch)], capture_output=True, text=True, env=env)
108
+ assert run.returncode == 2
109
+ assert json.loads(run.stdout)["results"][0]["errorCode"] == "PLUGIN_BATCH_INPUT_INVALID"
110
+
111
+ assert compile_plugin_source.time_accessor_issues(
112
+ '// row.getDate(START)\nrow.getInt(START); row.getDate("booking_date");', {"start_time"}
113
+ ) == []
114
+ assert len(compile_plugin_source.time_accessor_issues('row.getDate("start_time");', {"start_time"})) == 1
115
+
116
+
117
+ def test_timeprop_scan_ignores_literals_and_known_other_receivers_and_preserves_ambiguous_constants():
118
+ assert compile_plugin_source.time_accessor_issues(
119
+ 'class P { static final String START = "start_time"; String note = "Do not use row.getDate(START)"; }',
120
+ {"start_time"},
121
+ ) == []
122
+ assert compile_plugin_source.time_accessor_issues(
123
+ 'class P { void run(java.sql.ResultSet rs) { rs.getDate("start_time"); } }', {"start_time"},
124
+ ) == []
125
+ issues = compile_plugin_source.time_accessor_issues(
126
+ 'class P { static final String FIELD = "start_time"; void run(DynamicObject row) { row.getDate(FIELD); } '
127
+ 'static class Other { static final String FIELD = "booking_date"; } }', {"start_time"},
128
+ )
129
+ assert len(issues) == 1
130
+ assert issues[0]["severity"] == "warning"
131
+ assert issues[0]["fieldKeys"] == ["start_time"]
132
+
133
+
42
134
  def test_a_chinese_placeholder_word_in_a_comment_is_not_an_unresolved_dependency(tmp_path):
43
135
  """The word is ordinary business vocabulary. Scanning comments for it stopped delivery as
44
- L3-BLOCK on a correct Chinese comment, while the same word in a literal is a real placeholder."""
136
+ L3-BLOCK on a correct Chinese comment or a legitimate state/message string."""
45
137
  project_root = tmp_path / "module"
46
138
  source = project_root / "src" / "main" / "java" / "demo" / "Task.java"
47
139
  source.parent.mkdir(parents=True)
@@ -62,8 +154,11 @@ def test_a_chinese_placeholder_word_in_a_comment_is_not_an_unresolved_dependency
62
154
  encoding="utf-8",
63
155
  )
64
156
 
157
+ assert validate_source(source, project_root, "Task") == []
158
+
159
+ source.write_text('class Task { String reason = "待替换"; }', encoding="utf-8")
65
160
  assert validate_source(source, project_root, "Task") == [
66
- {"line": 2, "message": "unresolved placeholder text"},
161
+ {"line": 1, "message": "unresolved placeholder text"},
67
162
  ]
68
163
 
69
164
 
@@ -173,10 +268,29 @@ def test_compile_success_archives_before_marking_source_ready(tmp_path, monkeypa
173
268
 
174
269
  archive = json.loads((app_root / "archive.json").read_text(encoding="utf-8"))
175
270
  assert result["status"] is True
271
+ assert result["buildContext"]["gradleRoot"] == str(gradle_root.resolve())
272
+ assert result["buildContext"]["testTaskCandidate"] == ":demo:test"
273
+ assert result["sourceReview"]["businessCoverage"] == "not-established-by-compilation"
176
274
  assert archive["javas"][0]["className"] == "Task"
177
275
  assert (project_root / ".temp" / ".Task-gate").read_text() == "source_ready"
178
276
 
179
277
 
278
+ def test_operation_dispatch_preflight_flags_unverified_map_keys_and_unselected_shared_effects():
279
+ source = '''class Plugin {
280
+ String operation() { return (String) this.operateMeta.get("operationKey"); }
281
+ void beginOperationTransaction(Event event) { updateRelatedObject(); }
282
+ }'''
283
+ warnings = compile_plugin_source.operation_dispatch_warnings(source, ["save", "confirm"])
284
+ assert {warning["errorCode"] for warning in warnings} == {
285
+ "PLUGIN_OPERATION_MAP_KEY_UNVERIFIED", "PLUGIN_OPERATION_SCOPE_UNVERIFIED"}
286
+ assert all(warning["severity"] == "warning" for warning in warnings)
287
+ assert compile_plugin_source.operation_dispatch_warnings(
288
+ 'class P { String example="operateMeta.get(\\"operationKey\\")"; '
289
+ 'void beginOperationTransaction(Event event) { if (expected.equals(event.getOperationKey())) updateRelatedObject(); } }',
290
+ ["save", "confirm"],
291
+ ) == []
292
+
293
+
180
294
  def test_compile_refuses_a_method_declared_twice_even_when_compilation_is_disabled(tmp_path, monkeypatch):
181
295
  project_root = tmp_path / "module"
182
296
  source = project_root / "src" / "main" / "java" / "demo" / "Bill.java"
@@ -563,7 +677,7 @@ def test_a_comment_placeholder_after_a_form_feed_is_still_located(tmp_path):
563
677
  source.write_text(
564
678
  "class Task {\n"
565
679
  " /* page\x0cbreak */\n"
566
- ' void run() { String s = "待确认"; }\n'
680
+ ' void run() { String s = "占位实现"; }\n'
567
681
  "}\n",
568
682
  encoding="utf-8",
569
683
  )
@@ -649,3 +763,110 @@ def test_compile_refuses_a_drifted_override_even_when_compilation_is_disabled(tm
649
763
  assert result["issues"][0]["registeredSignatures"] == ["propertyChanged(PropertyChangedArgs)"]
650
764
  assert not (app_root / "archive.json").exists()
651
765
  assert not (project_root / ".temp").exists()
766
+
767
+
768
+ def test_batch_builds_one_module_once_and_keeps_full_diagnostics_in_one_log(tmp_path, monkeypatch, capsys):
769
+ project = tmp_path / "module"
770
+ java = project / "src/main/java/demo"
771
+ java.mkdir(parents=True)
772
+ (project / "settings.gradle").write_text("")
773
+ entries = []
774
+ for i in range(6):
775
+ source = java / f"Task{i}.java"
776
+ source.write_text(f"package demo; public class Task{i} {{}}")
777
+ entries.append({"sourcePath": str(source), "className": f"Task{i}", "type": "task",
778
+ "formNumber": "example", "operationKeys": [], "description": "scheduled task"})
779
+ batch = tmp_path / "sources.json"
780
+ batch.write_text(json.dumps(entries))
781
+ calls = []
782
+ diagnostics = "\n".join(f"{java / f'Task{i % 6}.java'}:{i+1}: error: missing symbol {i}" for i in range(60))
783
+ monkeypatch.setattr(compile_plugin_source, "inspect_config", lambda **_: {
784
+ "status": "ready", "GRADLE_ROOT": str(project), "JAVA_HOME": str(tmp_path / "jdk"),
785
+ })
786
+ def build(argv, **kwargs):
787
+ calls.append(argv)
788
+ return SimpleNamespace(returncode=1, stdout=diagnostics)
789
+ monkeypatch.setattr(compile_plugin_source.subprocess, "run", build)
790
+ monkeypatch.setattr(sys, "argv", ["compile_plugin_source.py", "--project-root", str(project),
791
+ "--app-root", str(tmp_path / "app"), "--sources-file", str(batch)])
792
+ assert compile_plugin_source.main() == 2
793
+ result = json.loads(capsys.readouterr().out)
794
+ assert len(calls) == 1
795
+ assert "--rerun-tasks" not in calls[0]
796
+ assert len(result["results"]) == 6
797
+ assert all(item["status"] is False for item in result["results"])
798
+ assert sum(len(item.get("diagnostics", [])) for item in result["results"]) == 5
799
+ paths = {item["logPath"] for item in result["results"]}
800
+ assert len(paths) == 1
801
+ assert Path(next(iter(paths))).read_text() == diagnostics
802
+ assert not (tmp_path / "app/archive.json").exists()
803
+ # Failures are not cached across invocations, so a recovered environment can be retried.
804
+ assert compile_plugin_source.main() == 2
805
+ capsys.readouterr()
806
+ assert len(calls) == 2
807
+ monkeypatch.setattr(compile_plugin_source.subprocess, "run",
808
+ lambda *a, **k: SimpleNamespace(returncode=0, stdout="BUILD SUCCESSFUL"))
809
+ assert compile_plugin_source.main() == 0
810
+ result = json.loads(capsys.readouterr().out)
811
+ assert all(item["status"] is True for item in result["results"])
812
+ archive = json.loads((tmp_path / "app/archive.json").read_text())
813
+ assert len(archive["javas"]) == 6
814
+ assert all(item["compileStatus"] == "passed" and len(item["sourceHash"]) == 64 for item in archive["javas"])
815
+
816
+
817
+ def test_failed_recompile_invalidates_prior_archive_readiness(tmp_path, monkeypatch):
818
+ project = tmp_path / "module"
819
+ source = project / "src/main/java/demo/Task.java"
820
+ source.parent.mkdir(parents=True)
821
+ source.write_text("package demo; public class Task {}")
822
+ (project / "settings.gradle").write_text("")
823
+ app = tmp_path / "app"
824
+ monkeypatch.setattr(compile_plugin_source, "inspect_config", lambda **_: {"status": "disabled"})
825
+ args = dict(app_root=app, plugin_type="task", form_number="example", operation_keys=[], description="scheduled task")
826
+ assert compile_plugin_source.compile_source(project, source, "Task", 30, **args)["status"]
827
+ assert json.loads((app / "archive.json").read_text())["javas"][0]["compileStatus"] == "skipped-by-config"
828
+ monkeypatch.setattr(compile_plugin_source, "inspect_config", lambda **_: {
829
+ "status": "ready", "GRADLE_ROOT": str(project), "JAVA_HOME": str(tmp_path / "jdk"),
830
+ })
831
+ monkeypatch.setattr(compile_plugin_source.subprocess, "run", lambda *a, **k: SimpleNamespace(returncode=1, stdout="dependency resolution failed"))
832
+ assert compile_plugin_source.compile_source(project, source, "Task", 30, **args)["status"] is False
833
+ assert json.loads((app / "archive.json").read_text())["javas"][0]["compileStatus"] == "pending"
834
+
835
+
836
+ def test_compile_reports_independent_source_issues_together(tmp_path):
837
+ source = tmp_path / "src" / "main" / "java" / "sample" / "Example.java"
838
+ source.parent.mkdir(parents=True)
839
+ source.write_text('''package sample;
840
+ import kd.bos.servicehelper.QueryServiceHelper;
841
+ import kd.bos.dataentity.entity.DynamicObject;
842
+ import kd.bos.orm.query.QFilter;
843
+ class Example {
844
+ void run() {
845
+ DynamicObject[] values = QueryServiceHelper.query("sample", "id", null);
846
+ QFilter filter = new QFilter("id", "not in", null);
847
+ }
848
+ }
849
+ ''')
850
+ result = compile_plugin_source.compile_source(tmp_path, source, "Example", 10, app_root=tmp_path / "app",
851
+ plugin_type="operation", form_number="sample", operation_keys=["process"], description="check")
852
+ assert set(result["errorCodes"]) >= {"PLUGIN_SOURCE_RETURN_TYPE_MISMATCH", "PLUGIN_SOURCE_QFILTER_STRING_OPERATOR"}
853
+ assert all(issue["errorCode"] in result["errorCodes"] for issue in result["issues"])
854
+ assert not (tmp_path / "app" / "archive.json").exists()
855
+
856
+
857
+ def test_compile_consumes_handoff_without_retyped_identity(tmp_path, monkeypatch, capsys):
858
+ source = tmp_path / "src" / "main" / "java" / "sample" / "Example.java"
859
+ source.parent.mkdir(parents=True)
860
+ source.write_text("package sample; public class Example {}")
861
+ prepared = tmp_path / "handoff.json"
862
+ prepared.write_text(json.dumps({"status": True, "handoff": {"projectRoot": str(tmp_path),
863
+ "appRoot": str(tmp_path / "app"), "sourcePath": str(source), "className": "Example", "type": "task",
864
+ "formNumber": "sample", "operationKeys": [], "description": "check"}}))
865
+ monkeypatch.setattr(compile_plugin_source, "inspect_config", lambda write_derived: {"status": "disabled", "compile": False})
866
+ monkeypatch.setattr(sys, "argv", ["compile_plugin_source.py", "--handoff", str(prepared)])
867
+ assert compile_plugin_source.main() == 0
868
+ result = json.loads(capsys.readouterr().out)
869
+ assert result["compileSkipped"] is True
870
+ archive = json.loads((tmp_path / "app" / "archive.json").read_text())
871
+ assert archive["javas"][0]["className"] == "Example"
872
+ assert archive["javas"][0]["filePath"] == str(source.resolve())