@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
@@ -65,6 +65,7 @@ from naming_rules import ( # type: ignore
65
65
  MAX_FIELD_KEY_LEN,
66
66
  MAX_COLUMN_NAME_LEN,
67
67
  MAX_TABLE_NAME_LEN,
68
+ MAX_ENTITY_KEY_LEN,
68
69
  compute_budgets,
69
70
  trim_identifiers,
70
71
  validate_dynamic_form_number,
@@ -83,17 +84,16 @@ _standard_flag: bool | None = None
83
84
 
84
85
  def _is_standard(isv: str, standard: bool | None = None) -> bool:
85
86
  """Determine whether to use standard naming rules (no ISV prefix).
86
- Prefer the explicitly passed standard parameter; otherwise read the module-level
87
- _standard_flag; finally fall back to the isv=='kingdee' compatibility logic.
87
+
88
+ 本地补丁 #16:命名规则强制标准模式(preset 作者 2026-08-27)——原判定整段停用。
89
+ 上游逻辑(按参数/身份判定)保留在下方注释,便于对照与回退。
88
90
  """
89
- # 原逻辑(按参数/身份判定是否标准模式)已注释,强制统一 True:
91
+ # 上游原逻辑(已停用):
90
92
  # if standard is not None:
91
93
  # return bool(standard)
92
94
  # if _standard_flag is not None:
93
95
  # return bool(_standard_flag)
94
96
  # return isv.lower() == "kingdee" if isv else False
95
-
96
- # 命名规则强制标准模式(无 ISV 前缀,preset 作者 2026-08-27)
97
97
  return True
98
98
 
99
99
 
@@ -187,11 +187,10 @@ def make_entity_key_map(
187
187
  biz_name = str(entity.get("bizName") or "").strip()
188
188
  if not biz_name:
189
189
  continue
190
- entity_key = str(entity.get("logicalName") or "").strip() or (
191
- biz_name
192
- if _is_standard(isv, standard)
193
- else (f"{isv}_{biz_name}" if isv else biz_name)
194
- )
190
+ logical = str(entity.get("logicalName") or "").strip()
191
+ entity_key = _make_namespaced_key(logical or biz_name, isv, standard=standard)
192
+ if logical:
193
+ result[logical] = entity_key
195
194
  result[biz_name] = entity_key
196
195
  result[entity_key] = entity_key
197
196
  result[_make_entity_key(biz_name, isv)] = entity_key
@@ -236,10 +235,10 @@ def _consume_physical_name(item: dict, generated: str) -> str:
236
235
  return physical or generated
237
236
 
238
237
 
239
- def _consume_logical_name(item: dict, generated: str) -> str:
238
+ def _consume_logical_name(item: dict, generated: str, isv: str = "") -> str:
240
239
  """Consume one optional exact persisted logical identifier."""
241
240
  logical = str(item.pop("logicalName", "") or "").strip()
242
- return logical or generated
241
+ return _make_namespaced_key(logical, isv) if logical else generated
243
242
 
244
243
 
245
244
  def _make_mul_basedata_table_name(entity_key: str, column_name: str) -> str:
@@ -376,7 +375,16 @@ def _check_lengths(entities: list) -> None:
376
375
  """在自动名与精确约束汇合后校验最终落库标识。"""
377
376
  identifier = re.compile(r"^[a-z][a-z0-9_]*$")
378
377
  seen_tables: set[str] = set()
378
+ seen_entities: set[str] = set()
379
+ seen_fields: set[str] = set()
379
380
  for ent in entities:
381
+ entity_key = str(ent.get("entityKey") or "")
382
+ limit = 36 if ent.get("type") == "MainEntity" else MAX_ENTITY_KEY_LEN
383
+ if len(entity_key) > limit:
384
+ raise ValueError(f"entityKey '{entity_key}' exceeds {limit} characters including developer prefix")
385
+ if entity_key in seen_entities:
386
+ raise ValueError(f"duplicate entityKey '{entity_key}'")
387
+ seen_entities.add(entity_key)
380
388
  tname = ent.get("tableName", "")
381
389
  if tname and not identifier.fullmatch(tname):
382
390
  raise ValueError(f"tableName '{tname}' is not a lowercase identifier")
@@ -390,6 +398,10 @@ def _check_lengths(entities: list) -> None:
390
398
  seen_columns: set[str] = set()
391
399
  for fld in ent.get("fields", []):
392
400
  fk = fld.get("fieldKey", "")
401
+ if fk and fk in seen_fields:
402
+ raise ValueError(f"duplicate fieldKey '{fk}'")
403
+ if fk:
404
+ seen_fields.add(fk)
393
405
  cn = fld.get("columnName", "")
394
406
  if fk and len(fk) > MAX_FIELD_KEY_LEN:
395
407
  raise ValueError(
@@ -522,6 +534,21 @@ def _replace_references(artifact: dict, mapping: dict) -> None:
522
534
  )
523
535
  properties["FireUpdEvt"] = True
524
536
 
537
+ # Operation parameter reference slots carry logical keys; message text,
538
+ # runtime IDs and arbitrary parameter values remain untouched.
539
+ def map_parameter_references(value):
540
+ if isinstance(value, list):
541
+ for item in value:
542
+ map_parameter_references(item)
543
+ if isinstance(value, dict):
544
+ for key, item in value.items():
545
+ if key.casefold() in {"fieldkey", "entitykey", "entrykey", "formnumber"} and isinstance(item, str):
546
+ value[key] = mapping.get(item, item)
547
+ else:
548
+ map_parameter_references(item)
549
+ for operation in artifact.get("operations", []):
550
+ map_parameter_references(operation.get("parameter"))
551
+
525
552
  # propertySettings
526
553
  field_keys_by_id = {
527
554
  str(field.get("id") or ""): str(field.get("fieldKey") or "")
@@ -644,9 +671,12 @@ def decorate_artifact(raw_artifact: dict, isv: str, app_number: str,
644
671
  f"The run command requires artifact in bizWord/bizName format, "
645
672
  f"not fieldKey/entityKey format."
646
673
  )
674
+ logical_entity = str(ent.get("logicalName") or "").strip()
647
675
  entity_key = _consume_logical_name(
648
- ent, _make_entity_key(biz_name, isv)
676
+ ent, _make_entity_key(biz_name, isv), isv
649
677
  )
678
+ if logical_entity:
679
+ mapping[logical_entity] = entity_key
650
680
  table_name = _consume_physical_name(
651
681
  ent, _make_table_name(entity_key, isv, biz_name)
652
682
  )
@@ -675,9 +705,12 @@ def decorate_artifact(raw_artifact: dict, isv: str, app_number: str,
675
705
  )
676
706
  # Collision detection (must pass max_bw, otherwise numeric suffix would exceed the 0.2 truncation budget)
677
707
  resolved = _resolve_collision(biz_word, reserved, seen, max_len=max_bw)
708
+ logical_field = str(fld.get("logicalName") or "").strip()
678
709
  field_key = _consume_logical_name(
679
- fld, _make_field_key(resolved, isv, app_number)
710
+ fld, _make_field_key(resolved, isv, app_number), isv
680
711
  )
712
+ if logical_field:
713
+ mapping[logical_field] = field_key
681
714
  column_name = _consume_physical_name(
682
715
  fld, _make_column_name(resolved, isv)
683
716
  )
@@ -0,0 +1,374 @@
1
+ import json
2
+ import builtins
3
+ from contextlib import contextmanager, ExitStack
4
+ from pathlib import Path
5
+ import subprocess
6
+ import sys
7
+ from unittest.mock import patch
8
+
9
+ import pytest
10
+
11
+ SCRIPTS = Path(__file__).resolve().parents[1]
12
+ sys.path.insert(0, str(SCRIPTS))
13
+ import cosmic_api
14
+ from _core.build_receipts import BuildReceipts
15
+ from _core import cmd_metaops
16
+ from _core.execution_errors import attach_execution_error
17
+ from execution_binding import execution_binding, validate_execution_binding
18
+
19
+
20
+ @contextmanager
21
+ def _isolated_cli():
22
+ from _core import config, formatters
23
+ with ExitStack() as stack:
24
+ stack.enter_context(patch.object(builtins, "print", builtins.print))
25
+ for owner, names in [(cosmic_api, ("_CLI_MACHINE_MODE", "_CLI_DELIVERY_ARGS", "_CLI_RESULT_EMITTED")),
26
+ (formatters, ("_stdout_mode", "_output_file", "_current_cmd", "_current_arg_hash"))]:
27
+ for name in names:
28
+ stack.enter_context(patch.object(owner, name, getattr(owner, name)))
29
+ for owner in (config, cosmic_api):
30
+ for name in ("RUNTIME_DIR", "TOKEN_CACHE", "BIZ_CACHE", "CONTEXT_MD", "CONFIG_MD",
31
+ "ARTIFACTS_DIR", "BATCH_MANIFESTS_DIR", "TEMP_ARTIFACT", "WORKSPACE_JSON", "_BOUND_APP_ROOT"):
32
+ stack.enter_context(patch.object(owner, name, getattr(owner, name, None), create=True))
33
+ yield
34
+
35
+
36
+ def _artifacts(tmp_path):
37
+ a = tmp_path / "base.json"
38
+ b = tmp_path / "bill.json"
39
+ data = {str(a): {"entities": [{"entityKey": "vendor_base"}]},
40
+ str(b): {"entities": [{"entityKey": "vendor_bill", "fields": [{"refBillNumber": "vendor_base"}]}]}}
41
+ for source, artifact in data.items():
42
+ Path(source).write_text(json.dumps(artifact), encoding="utf-8")
43
+ return data
44
+
45
+
46
+ def test_verified_dependency_receipt_survives_restart_and_only_pending_target_runs(tmp_path):
47
+ artifacts = _artifacts(tmp_path)
48
+ base, bill = artifacts
49
+ progress = BuildReceipts(tmp_path, "APP", {"baseUrl": "test"}, artifacts)
50
+ progress.start(base)
51
+ progress.finish(base, {"ok": True, "phase": "verify", "writeAttempted": True,
52
+ "verification": {"status": "pass"},
53
+ "result": {"data": {"entityResults": [{"formNumber": "vendor_base", "formId": "EXACT"}]}}})
54
+ progress.finish(bill, {"ok": False, "phase": "resolveRefBill", "writeAttempted": False})
55
+ resumed = BuildReceipts(tmp_path, "APP", {"baseUrl": "test"}, artifacts, resume_result=progress.result_path)
56
+ assert resumed.reused(base)["result"]["data"]["entityResults"][0]["formId"] == "EXACT"
57
+ assert resumed.reused(bill) is None
58
+ resumed.start(bill)
59
+ persisted = json.loads(resumed.result_path.read_text())
60
+ assert persisted["results"][1]["phase"] == "writeUnknown"
61
+ assert persisted["results"][1]["targetNumbers"] == ["vendor_bill"]
62
+
63
+
64
+ def test_unknown_write_cannot_be_replayed_or_adopted(tmp_path):
65
+ artifacts = _artifacts(tmp_path)
66
+ base = next(iter(artifacts))
67
+ progress = BuildReceipts(tmp_path, "APP", {}, artifacts)
68
+ progress.start(base)
69
+ with pytest.raises(ValueError, match="RECONCILIATION_REQUIRED"):
70
+ BuildReceipts(tmp_path, "APP", {}, artifacts, resume_result=progress.result_path)
71
+ copied = tmp_path / "regenerated.json"
72
+ copied.write_text(Path(base).read_text())
73
+ other = BuildReceipts(tmp_path, "APP", {}, {str(copied): artifacts[base]})
74
+ with pytest.raises(ValueError, match="RECONCILIATION_REQUIRED"):
75
+ other.start(str(copied))
76
+
77
+
78
+ def test_zero_write_failure_allows_corrected_input(tmp_path):
79
+ artifacts = _artifacts(tmp_path)
80
+ source = next(iter(artifacts))
81
+ progress = BuildReceipts(tmp_path, "APP", {}, artifacts)
82
+ progress.start(source)
83
+ progress.finish(source, {"ok": False, "phase": "preflight", "writeAttempted": False})
84
+ artifacts[source]["entities"][0]["entityKey"] = "vendor_renamed"
85
+ Path(source).write_text(json.dumps(artifacts[source]))
86
+ resumed = BuildReceipts(tmp_path, "APP", {}, artifacts, resume_result=progress.result_path)
87
+ resumed.start(source)
88
+ assert json.loads(resumed.result_path.read_text())["results"][0]["targetNumbers"] == ["vendor_renamed"]
89
+
90
+
91
+ def test_saved_input_and_environment_changes_require_narrow_repair(tmp_path):
92
+ artifacts = _artifacts(tmp_path)
93
+ source = next(iter(artifacts))
94
+ progress = BuildReceipts(tmp_path, "APP", {}, artifacts)
95
+ progress.start(source)
96
+ progress.finish(source, {"ok": True, "writeAttempted": True, "verification": {"status": "pass"}})
97
+ with pytest.raises(ValueError, match="IDENTITY_CHANGED"):
98
+ BuildReceipts(tmp_path, "OTHER", {}, artifacts, resume_result=progress.result_path)
99
+ Path(source).write_text(Path(source).read_text() + "\n")
100
+ with pytest.raises(ValueError, match="SAVED_TARGET_CHANGED"):
101
+ BuildReceipts(tmp_path, "APP", {}, artifacts, resume_result=progress.result_path)
102
+
103
+
104
+ def test_source_binding_rejects_old_copy_and_changed_revision(tmp_path):
105
+ context = tmp_path / "_runtime" / "context.json"
106
+ context.parent.mkdir()
107
+ context.write_text(json.dumps({"rootDir": str(tmp_path / "old-copy")}))
108
+ with pytest.raises(ValueError, match="SOURCE_MISMATCH"):
109
+ validate_execution_binding(tmp_path)
110
+ binding = execution_binding()
111
+ context.write_text(json.dumps({"executionBinding": {**binding, "revision": "old"}}))
112
+ with pytest.raises(ValueError, match="REVISION_MISMATCH"):
113
+ validate_execution_binding(tmp_path)
114
+ context.write_text(json.dumps({"executionBinding": binding}))
115
+ validate_execution_binding(tmp_path)
116
+
117
+
118
+ @pytest.mark.parametrize("code,category", [
119
+ ("REF_BILL_TARGET_UNRESOLVED", "identity_resolution"),
120
+ ("RULE_FIELD_UNRESOLVED", "identity_resolution"),
121
+ ("CONDITIONAL_CARRY_SOURCE_PROPERTY_UNAVAILABLE", "identity_resolution"),
122
+ ("RULE_SET_COMMAND_UNSUPPORTED", "input"),
123
+ ("FULL_METADATA_API_UNAVAILABLE", "capability_limit"),
124
+ ("HTTP_ERROR", "environment"),
125
+ ])
126
+ def test_reference_or_input_errors_do_not_claim_platform_limit(code, category):
127
+ result = attach_execution_error({"status": False, "errorCode": code, "writeAttempted": False})
128
+ assert result["errorCategory"] == category
129
+ assert result["capabilityLimitConfirmed"] == (category == "capability_limit")
130
+
131
+
132
+ @pytest.mark.parametrize("locale", ["", ".locales/zh"])
133
+ def test_cli_stdout_and_result_file_are_the_same_json_in_path_with_spaces(tmp_path, locale):
134
+ output = tmp_path / "result with spaces.json"
135
+ result = subprocess.run([sys.executable, str(SCRIPTS.parents[2] / locale / "skills" / "cosmic-meta-api" / "scripts" / "cosmic_api.py"), "--stdout", "--output", str(output),
136
+ "describeCommand", "runBatch"], capture_output=True, text=True)
137
+ assert result.returncode == 0, result.stderr
138
+ assert json.loads(result.stdout) == json.loads(output.read_text())
139
+ assert "--resume-result" in result.stdout
140
+ assert "argvPrefix" in result.stdout
141
+
142
+
143
+ @pytest.mark.parametrize("lookup,code", [
144
+ ({"status": True, "data": [{"formNumber": "vendor_bill", "formId": "OTHER", "appId": "OTHER_APP"}]}, "TARGET_ALREADY_EXISTS"),
145
+ ({"status": False, "message": "connection closed"}, "TARGET_LOOKUP_UNCONFIRMED"),
146
+ ])
147
+ def test_creation_conflict_and_network_failure_prevent_writes(lookup, code):
148
+ with patch("_core.cmd_forms.resolve_template_input", return_value="bos_billtpl"), \
149
+ patch.object(cmd_metaops, "do_query_forms", return_value=lookup), \
150
+ patch.object(cmd_metaops, "_api_call") as write:
151
+ result = cmd_metaops.do_build_meta({}, "token", {"entities": [{"entityKey": "vendor_bill"}]}, "APP", "UNIT")
152
+ assert result["errorCode"] == code
153
+ assert result["writeAttempted"] is False
154
+ write.assert_not_called()
155
+
156
+
157
+ def test_real_batch_entry_resumes_only_unwritten_dependent_and_binds_saved_id(tmp_path, monkeypatch):
158
+ from contextlib import ExitStack
159
+ import copy
160
+ import kd_env_loader
161
+ from _core import formatters
162
+ from _core import config
163
+ (tmp_path / "archive.json").write_text(json.dumps({"appCode": "test", "appId": "APP", "type": "cosmic"}))
164
+ artifacts = {}
165
+ for name in ("base", "bill"):
166
+ source = tmp_path / (name + ".json")
167
+ artifact = {"templateNumber": "bos_billtpl", "entities": [{
168
+ "id": name, "type": "BillEntity", "entityKey": "vendor_" + name,
169
+ "tableName": "t_" + name, "fields": [],
170
+ }]}
171
+ if name == "bill":
172
+ artifact["entities"][0]["fields"] = [{"fieldKey": "vendor_ref", "columnName": "fref",
173
+ "displayName": "Reference", "dataType": "RefBillField", "refBillTargetNumber": "vendor_base"}]
174
+ source.write_text(json.dumps(artifact))
175
+ artifacts[str(source)] = artifact
176
+ base, bill = artifacts
177
+ prior = BuildReceipts(tmp_path, "APP", {}, artifacts, options=["--bizAppId", "APP"])
178
+ prior.start(base)
179
+ saved = {"status": True, "data": {"entityResults": [{"entityId": "base", "formId": "SAVED-EXACT-ID",
180
+ "formNumber": "vendor_base", "entityKey": "vendor_base", "success": True}], "successCount": 1}}
181
+ prior.finish(base, {"ok": True, "phase": "verify", "writeAttempted": True,
182
+ "result": saved, "verification": {"status": "pass"},
183
+ "summary": cosmic_api._summarize_build_meta_result(saved)})
184
+ prior.finish(bill, {"ok": False, "phase": "dependency", "writeAttempted": False})
185
+ emitted = []
186
+ build_inputs = []
187
+ modification_inputs = []
188
+
189
+ def build(cfg, token, artifact, **kwargs):
190
+ build_inputs.append(copy.deepcopy(artifact))
191
+ return {"status": True, "data": {"entityResults": [{"entityId": "bill", "formId": "NEW-BILL-ID",
192
+ "formNumber": "vendor_bill", "entityKey": "vendor_bill", "success": True}], "successCount": 1}}
193
+
194
+ def modify(cfg, token, **kwargs):
195
+ modification_inputs.append(kwargs)
196
+ return {"status": True, "verification": {"verified": True}}
197
+
198
+ monkeypatch.setattr(sys, "argv", [str(SCRIPTS / "cosmic_api.py"), "--stdout", "runBatch", "--app-root", str(tmp_path),
199
+ "--resume-result", str(prior.result_path), "--verify", "--no-sync-dym", "--artifacts", base, bill])
200
+ monkeypatch.setenv("PROJECT_ROOT", str(tmp_path))
201
+ with _isolated_cli(), ExitStack() as stack:
202
+ for owner, name, value in [
203
+ (cosmic_api, "load_config", lambda: {}),
204
+ (cosmic_api, "_load_workspace_for_write", lambda *a, **k: {"isv": "vendor", "appNumber": "test", "bizAppId": "APP"}),
205
+ (cosmic_api, "do_auth", lambda *a, **k: "test-token"),
206
+ (cosmic_api, "do_build_meta", build),
207
+ (cosmic_api, "do_modify_meta", modify),
208
+ (cosmic_api, "do_get_properties", lambda *a, **k: {"status": True, "data": {"billEntityId": "SAVED-EXACT-ID"}}),
209
+ (cosmic_api, "_verify_build_meta_readback", lambda *a: {"status": "pass"}),
210
+ (cosmic_api, "_append_meta_event", lambda *a, **k: None),
211
+ (cosmic_api, "_archive_finalize_metadata", lambda *a, **k: None),
212
+ (cosmic_api, "_attach_available_form_numbers", lambda c, t, r: r),
213
+ (cosmic_api, "pjson", emitted.append),
214
+ (kd_env_loader, "load_environment_identity", lambda: {}),
215
+ ]:
216
+ stack.enter_context(patch.object(owner, name, value))
217
+ stack.enter_context(patch.object(cosmic_api, "do_query_forms", side_effect=AssertionError("The saved identity must come from its receipt")))
218
+ # Isolate mutable process paths and stdout mode from subsequent tests.
219
+ stack.enter_context(patch.object(config, "RUNTIME_DIR", str(tmp_path / "_runtime")))
220
+ stack.enter_context(patch.object(config, "_BOUND_APP_ROOT", str(tmp_path), create=True))
221
+ stack.enter_context(patch.object(formatters, "_stdout_mode", False))
222
+ cosmic_api._main_impl()
223
+ assert len(build_inputs) == 1
224
+ assert build_inputs[0]["entities"][0]["entityKey"] == "vendor_bill"
225
+ assert len(modification_inputs) == 1
226
+ assert modification_inputs[0]["ops"][0]["value"]["billEntityId"] == "SAVED-EXACT-ID"
227
+ assert emitted[-1]["success"] == 2
228
+ assert emitted[-1]["results"][0]["reusedReceipt"] is True
229
+ assert json.loads(Path(emitted[-1]["resultPath"]).read_text())["success"] == 2
230
+
231
+
232
+ @pytest.mark.parametrize("present", [False, True])
233
+ def test_read_only_reconciliation_releases_only_proven_absent_target(tmp_path, monkeypatch, present):
234
+ from contextlib import ExitStack
235
+ import kd_env_loader
236
+ from _core.build_receipts import _atomic_json
237
+ artifact = {"templateNumber": "bos_billtpl", "entities": [{"id": "root", "type": "BillEntity",
238
+ "entityKey": "vendor_unknown", "tableName": "t_unknown", "fields": []}]}
239
+ source = tmp_path / "unknown.json"
240
+ source.write_text(json.dumps(artifact))
241
+ (tmp_path / "archive.json").write_text(json.dumps({"appCode": "test", "appId": "APP", "type": "cosmic"}))
242
+ progress = BuildReceipts(tmp_path, "APP", {}, {str(source): artifact}, options=["--bizAppId", "APP"])
243
+ progress.start(str(source))
244
+ # Simulate a completed command that received no trustworthy write response.
245
+ progress.receipt["executionFinished"] = True
246
+ _atomic_json(progress.result_path, progress.receipt)
247
+ emitted = []
248
+ monkeypatch.setattr(sys, "argv", [str(SCRIPTS / "cosmic_api.py"), "--stdout", "runBatch", "--app-root", str(tmp_path),
249
+ "--resume-result", str(progress.result_path), "--reconcile-only", "--verify", "--artifacts", str(source)])
250
+ monkeypatch.setenv("PROJECT_ROOT", str(tmp_path))
251
+ with _isolated_cli(), ExitStack() as stack:
252
+ for owner, name, value in [
253
+ (cosmic_api, "load_config", lambda: {}),
254
+ (cosmic_api, "_load_workspace_for_write", lambda *a, **k: {"isv": "vendor", "appNumber": "test", "bizAppId": "APP"}),
255
+ (cosmic_api, "do_auth", lambda *a, **k: "test-token"),
256
+ (cosmic_api, "do_query_forms", lambda *a, **k: {"status": True, "data": [{"formNumber": "vendor_unknown", "formId": "UNRELATED"}] if present else []}),
257
+ (cosmic_api, "_append_meta_event", lambda *a, **k: None),
258
+ (cosmic_api, "pjson", emitted.append),
259
+ (kd_env_loader, "load_environment_identity", lambda: {}),
260
+ ]:
261
+ stack.enter_context(patch.object(owner, name, value))
262
+ build = stack.enter_context(patch.object(cosmic_api, "do_build_meta"))
263
+ with pytest.raises(SystemExit):
264
+ cosmic_api._main_impl()
265
+ build.assert_not_called()
266
+ result = emitted[-1]
267
+ assert result["resume"]["ready"] is (not present)
268
+ assert result["results"][0]["phase"] == ("writeUnknown" if present else "reconciledAbsent")
269
+ if not present:
270
+ assert result["results"][0]["writeAttempted"] is False
271
+ resumed = BuildReceipts(tmp_path, "APP", {}, {str(source): artifact},
272
+ options=["--bizAppId", "APP"], resume_result=result["resultPath"])
273
+ resumed.start(str(source))
274
+ else:
275
+ assert result["results"][0].get("ok") is False
276
+ assert not result.get("forms")
277
+
278
+
279
+ def test_reconciliation_refuses_an_active_original_process(tmp_path):
280
+ artifacts = _artifacts(tmp_path)
281
+ progress = BuildReceipts(tmp_path, "APP", {}, artifacts)
282
+ progress.start(next(iter(artifacts)))
283
+ with pytest.raises(ValueError, match="still active"):
284
+ BuildReceipts(tmp_path, "APP", {}, artifacts, resume_result=progress.result_path, reconcile_only=True)
285
+
286
+
287
+ def test_bootstrap_machine_failure_stays_parseable(tmp_path):
288
+ result = subprocess.run([sys.executable, str(SCRIPTS.parents[2] / "scripts" / "bootstrap_cosmic_context.py"),
289
+ "--stdout", "--project-root", str(tmp_path)], capture_output=True, text=True)
290
+ assert result.returncode != 0
291
+ assert json.loads(result.stdout)["status"] is False
292
+ assert "executionBinding" in result.stdout
293
+
294
+
295
+ def test_serve_keeps_protocol_stdout_when_diagnostics_are_routed(capsys):
296
+ import io
297
+ with _isolated_cli(), patch.object(cosmic_api, "do_auth", return_value="test-token"), \
298
+ patch.object(sys, "stdin", io.StringIO('{"cmd":"ping"}\n{"cmd":"exit"}\n')):
299
+ cosmic_api._route_unstructured_prints_to_stderr()
300
+ cosmic_api._serve_loop({})
301
+ lines = capsys.readouterr().out.splitlines()
302
+ assert lines[0] == "###SERVE_READY###"
303
+ assert json.loads(lines[1]) == {"success": True, "data": "pong"}
304
+
305
+
306
+ def test_root_identity_is_persisted_before_independent_readback(tmp_path):
307
+ artifacts = _artifacts(tmp_path)
308
+ source = next(iter(artifacts))
309
+ progress = BuildReceipts(tmp_path, "APP", {}, artifacts)
310
+ progress.start(source)
311
+ response = {"status": True, "data": {"entityResults": [{"entityKey": "vendor_base",
312
+ "formId": "SAVED-BEFORE-READ", "success": True}]}}
313
+ with patch("_core.cmd_forms.resolve_template_input", return_value="bos_billtpl"), \
314
+ patch.object(cmd_metaops, "do_query_forms", return_value={"status": True, "data": []}), \
315
+ patch.object(cmd_metaops, "_api_call", return_value=response), \
316
+ patch("_core.cmd_forms.do_get_form_schema", side_effect=RuntimeError("read interrupted")):
317
+ result = cmd_metaops.do_build_meta({}, "token", artifacts[source], "APP", "UNIT",
318
+ on_write_result=lambda received: progress.finish(source, {
319
+ "ok": False, "phase": "rootReceipt", "writeAttempted": True, "result": received}))
320
+ persisted = json.loads(progress.result_path.read_text())
321
+ assert persisted["results"][0]["result"]["data"]["entityResults"][0]["formId"] == "SAVED-BEFORE-READ"
322
+ assert result["status"] is False
323
+ assert persisted["resume"]["ready"] is False
324
+
325
+
326
+ @pytest.mark.parametrize("reader", ["_core.cmd_forms.resolve_template_input", "_core.cmd_metaops.do_query_forms"])
327
+ def test_precreate_read_exception_is_confirmed_unwritten(reader):
328
+ with patch("_core.cmd_forms.resolve_template_input", return_value="bos_billtpl"), \
329
+ patch("_core.cmd_metaops.do_query_forms", return_value={"status": True, "data": []}), \
330
+ patch(reader, side_effect=ConnectionResetError("injected pre-write network failure")), \
331
+ patch.object(cmd_metaops, "_api_call") as write:
332
+ result = cmd_metaops.do_build_meta({}, "token", {"entities": [{"entityKey": "vendor_probe"}]}, "APP", "UNIT")
333
+ assert result["writeAttempted"] is False
334
+ assert attach_execution_error(result)["errorCategory"] == "environment"
335
+ write.assert_not_called()
336
+
337
+
338
+ def test_verified_receipt_clears_intermediate_error_category(tmp_path):
339
+ artifacts = _artifacts(tmp_path)
340
+ source = next(iter(artifacts))
341
+ progress = BuildReceipts(tmp_path, "APP", {}, artifacts)
342
+ progress.start(source)
343
+ progress.finish(source, {"ok": False, "phase": "rootReceipt", "writeAttempted": True})
344
+ final = progress.finish(source, {"ok": True, "phase": "verify", "verification": {"status": "pass"}})
345
+ assert "errorCategory" not in final
346
+ assert "capabilityLimitConfirmed" not in final
347
+
348
+
349
+ @pytest.mark.parametrize("attempts,expected", [([False], False), ([True, False], True), ([None, False], None)])
350
+ def test_batch_summary_preserves_actual_write_boundary(attempts, expected):
351
+ result = cosmic_api._summarize_run_batch({"failed": len(attempts), "success": 0, "results": [
352
+ {"ok": False, "writeAttempted": value, "summary": {"ok": False, "targetConflicts": [
353
+ {"formNumber": "vendor_existing"}], "writeAttempted": value}}
354
+ for value in attempts
355
+ ]})
356
+ assert result["writeAttempted"] is expected
357
+
358
+
359
+ def test_execution_revision_includes_root_payload_schemas(tmp_path):
360
+ import execution_binding as binding_module
361
+ (tmp_path / "scripts").mkdir()
362
+ (tmp_path / "schemas").mkdir()
363
+ (tmp_path / "SKILL.md").write_text("fixture")
364
+ schema = tmp_path / "schemas" / "payload.json"
365
+ schema.write_text('{"required":["first"]}')
366
+ binding_module.execution_binding.cache_clear()
367
+ try:
368
+ with patch.object(binding_module, "__file__", str(tmp_path / "scripts" / "execution_binding.py")):
369
+ first = binding_module.execution_binding()["revision"]
370
+ schema.write_text('{"required":["second"]}')
371
+ binding_module.execution_binding.cache_clear()
372
+ assert binding_module.execution_binding()["revision"] != first
373
+ finally:
374
+ binding_module.execution_binding.cache_clear()
@@ -25,6 +25,30 @@ from _core import number_validator # noqa: E402
25
25
  from _core import cmd_rules # noqa: E402
26
26
 
27
27
 
28
+ def test_combo_read_failure_preserves_cause_and_does_not_claim_options_absent():
29
+ from _core import cmd_fields
30
+ failure = {"status": False, "errorCode": "406",
31
+ "message": "kd.bos.designer.build.FullMetadataApiService not find"}
32
+ with mock.patch.object(cmd_fields, "_api_call", return_value=failure):
33
+ result = cmd_fields._combo_verify_after_modify(
34
+ {}, "token", "uhyl_dish", "uhyl_dish_status",
35
+ [{"label": "供应中", "value": "available"}], None,
36
+ )
37
+ assert result["status"] == "readback_failed"
38
+ assert result["cause"] == failure
39
+ assert "FullMetadataApiService not find" in result["message"]
40
+ assert "absent" not in result["message"]
41
+
42
+
43
+ def test_combo_remove_read_failure_cannot_report_success():
44
+ from _core import cmd_fields
45
+ with mock.patch.object(cmd_fields, "_api_call", return_value={"status": False}):
46
+ result = cmd_fields._combo_verify_after_modify(
47
+ {}, "token", "uhyl_dish", "uhyl_dish_status", [], "sold_out",
48
+ )
49
+ assert result["status"] == "readback_failed"
50
+
51
+
28
52
  @pytest.mark.parametrize("readback", [
29
53
  {"status": False, "message": "read unavailable"},
30
54
  {"status": True, "data": {"Items": [{"_Type_": "BizRule", "Id": "r", "PreCondition": "amount > 200"}]}},
@@ -30,7 +30,9 @@ def test_build_uses_observed_identity_and_schema_aware_trigger_writer():
30
30
  "propertySettings": [{"elementKey": "field", "settingType": "simple", "properties": {"FireUpdEvt": True}}]}
31
31
  original = copy.deepcopy(artifact)
32
32
  result = {"status": True, "data": {"entityResults": [{"entityId": "e1", "entityKey": "vendor_Mixed", "formId": "id", "success": True}]}}
33
- with patch("_core.cmd_metaops._api_call", return_value=result) as build, patch(
33
+ with patch("_core.cmd_forms.resolve_template_input", return_value="bos_billtpl"), patch(
34
+ "_core.cmd_metaops.do_query_forms", return_value={"status": True, "data": []},
35
+ ), patch("_core.cmd_metaops._api_call", return_value=result) as build, patch(
34
36
  "_core.cmd_forms.do_get_form_schema", return_value={"status": True, "data": {"formNumber": "vendor_mixed"}},
35
37
  ), patch("_core.cmd_properties.do_set_properties_verified", return_value={"status": True, "verification": {"verified": True}}) as setter:
36
38
  actual = do_build_meta({}, "token", artifact, "app", "unit")
@@ -42,7 +44,7 @@ def test_build_uses_observed_identity_and_schema_aware_trigger_writer():
42
44
 
43
45
  def test_partial_build_exposes_observed_fields_and_does_not_write_more():
44
46
  result = {"status": True, "data": {"entityResults": [{"formId": "id", "success": False}]}}
45
- with patch("_core.cmd_metaops._api_call", return_value=result), patch(
47
+ with patch("_core.cmd_forms.resolve_template_input", return_value="bos_billtpl"), patch("_core.cmd_metaops._api_call", return_value=result), patch(
46
48
  "_core.cmd_forms.do_get_form_schema", return_value={"status": True, "data": {"formNumber": "existing", "entities": [{"fields": [{"fieldKey": "field"}]}]}},
47
49
  ), patch("_core.cmd_properties.do_set_properties_verified") as setter:
48
50
  actual = do_build_meta({}, "token", {"entities": []}, "app", "unit")