@tencent-rtc/trtc-agent-skills 0.1.1 → 0.1.4

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 (366) hide show
  1. package/.cursor/rules/main.mdc +12 -0
  2. package/AGENTS.md +14 -97
  3. package/CLAUDE.md +15 -120
  4. package/CODEBUDDY.md +32 -118
  5. package/README.md +7 -5
  6. package/README.zh.md +7 -5
  7. package/bin/cli.js +133 -41
  8. package/hooks/__pycache__/cursor-adapter.cpython-313.pyc +0 -0
  9. package/hooks/cursor-adapter.py +45 -18
  10. package/hooks/hooks-cursor.json +5 -18
  11. package/hooks/hooks.json +6 -31
  12. package/knowledge-base/conference/web/index.yaml +143 -0
  13. package/knowledge-base/platform-slice-template.md +1041 -133
  14. package/knowledge-base/products.yaml +76 -0
  15. package/knowledge-base/scenario-spec.md +1316 -115
  16. package/knowledge-base/scenarios/conference/base/general-conference.md +26 -3
  17. package/knowledge-base/scenarios/conference/base/webinar-conference.md +14 -0
  18. package/knowledge-base/scenarios/conference/medical/1v1-video-consultation.md +19 -0
  19. package/knowledge-base/scenarios/conference/medical/medical-multidoctor-consultation.md +13 -0
  20. package/knowledge-base/scenarios/live/entertainment-live-room.md +12 -0
  21. package/knowledge-base/slice-spec.md +2377 -299
  22. package/knowledge-base/slices/conference/web/integration-audit.md +155 -0
  23. package/knowledge-base/slices/conference/web/login-auth.md +16 -2
  24. package/knowledge-base/slices/conference/web/official-roomkit-login-ui.md +41 -13
  25. package/knowledge-base/slices/conference/web/prejoin-check.md +8 -5
  26. package/knowledge-base/tooling/aliases.yaml +92 -0
  27. package/knowledge-base/tooling/intent-signals.yaml +181 -0
  28. package/knowledge-base/tooling/symptom-keywords.yaml +21 -0
  29. package/package.json +1 -1
  30. package/skills/trtc/SKILL.md +202 -244
  31. package/skills/trtc/hooks/__pycache__/report_prompt.cpython-313.pyc +0 -0
  32. package/skills/{trtc-topic/guardrails → trtc/hooks}/gate_slice_read.py +12 -8
  33. package/skills/{trtc-topic/guardrails → trtc/hooks}/gate_slice_write.py +16 -12
  34. package/skills/{trtc-topic/guardrails → trtc/hooks}/stop_require_apply_evidence.py +22 -14
  35. package/skills/trtc/hooks/topic_phase_gate.py +161 -0
  36. package/skills/trtc/room-builder/assets/local-usersig/basic-info-config.ts +39 -0
  37. package/skills/trtc/room-builder/assets/local-usersig/lib-generate-test-usersig-es.min.d.ts +4 -0
  38. package/skills/trtc/room-builder/assets/local-usersig/lib-generate-test-usersig-es.min.js +2 -0
  39. package/skills/{trtc-topic → trtc}/runtime/README.md +2 -2
  40. package/skills/{trtc-onboarding/reference/reporting-protocol.md → trtc/runtime/REPORTING.md} +5 -3
  41. package/skills/{trtc-topic → trtc}/runtime/RUNTIME.md +5 -5
  42. package/skills/trtc/runtime/lib/__init__.py +0 -0
  43. package/skills/{trtc-topic → trtc}/runtime/package-lock.json +2 -2
  44. package/skills/{trtc-topic → trtc}/runtime/package.json +2 -2
  45. package/skills/{trtc-topic → trtc}/runtime/telemetry-bridge.mjs +1 -1
  46. package/skills/trtc/runtime/usersig-handling.md +134 -0
  47. package/skills/{trtc-topic/scripts → trtc/tools}/STATE-MACHINE-GUIDE.md +23 -23
  48. package/skills/trtc/tools/__init__.py +2 -0
  49. package/skills/trtc/tools/__pycache__/__init__.cpython-313.pyc +0 -0
  50. package/skills/trtc/tools/__pycache__/query_classifier.cpython-313.pyc +0 -0
  51. package/skills/trtc/tools/__pycache__/reporting.cpython-313.pyc +0 -0
  52. package/skills/trtc/tools/__pycache__/search.cpython-313.pyc +0 -0
  53. package/skills/trtc/tools/__pycache__/session.cpython-313.pyc +0 -0
  54. package/skills/trtc/tools/apply.py +540 -0
  55. package/skills/trtc/tools/docs.py +712 -0
  56. package/skills/trtc/tools/docsbot.py +182 -0
  57. package/skills/trtc/tools/entry/render_ai_instructions.py +92 -0
  58. package/skills/trtc/tools/flow.py +1089 -0
  59. package/skills/{trtc-topic/scripts → trtc/tools}/init_slice_queue.py +5 -4
  60. package/skills/{trtc-topic/scripts → trtc/tools}/next_slice.py +5 -4
  61. package/skills/trtc/tools/query_classifier.py +301 -0
  62. package/skills/trtc/tools/reporting.py +447 -0
  63. package/skills/trtc/tools/search.py +817 -0
  64. package/skills/trtc/tools/session.py +1261 -0
  65. package/skills/trtc/tools/state_machine.py +690 -0
  66. package/skills/trtc-ai-service/README.md +195 -0
  67. package/skills/trtc-ai-service/README.zh-CN.md +193 -0
  68. package/skills/trtc-ai-service/SKILL.md +945 -0
  69. package/skills/trtc-ai-service/auto_adapters/README.md +40 -0
  70. package/skills/trtc-ai-service/auto_adapters/frontend-spa/README.md +27 -0
  71. package/skills/trtc-ai-service/auto_adapters/frontend-spa/angular/voice-agent.component.ts.tpl +131 -0
  72. package/skills/trtc-ai-service/auto_adapters/frontend-spa/manifest.yaml +57 -0
  73. package/skills/trtc-ai-service/auto_adapters/frontend-spa/react/VoiceAgent.tsx.tpl +142 -0
  74. package/skills/trtc-ai-service/auto_adapters/frontend-spa/vue/VoiceAgent.vue.tpl +121 -0
  75. package/skills/trtc-ai-service/auto_adapters/integration_templates/generic-backend.md +45 -0
  76. package/skills/trtc-ai-service/auto_adapters/integration_templates/generic-frontend.md +51 -0
  77. package/skills/trtc-ai-service/auto_adapters/integration_templates/generic-rest-api.md +93 -0
  78. package/skills/trtc-ai-service/auto_adapters/java-backend/README.md +25 -0
  79. package/skills/trtc-ai-service/auto_adapters/java-backend/manifest.yaml +30 -0
  80. package/skills/trtc-ai-service/auto_adapters/java-backend/quarkus/VoiceAgentFilter.java.tpl +64 -0
  81. package/skills/trtc-ai-service/auto_adapters/java-backend/springboot/VoiceAgentFilter.java.tpl +91 -0
  82. package/skills/trtc-ai-service/auto_adapters/manifest.yaml +43 -0
  83. package/skills/trtc-ai-service/auto_adapters/node-backend/README.md +25 -0
  84. package/skills/trtc-ai-service/auto_adapters/node-backend/express.js.tpl +40 -0
  85. package/skills/trtc-ai-service/auto_adapters/node-backend/fastify.js.tpl +27 -0
  86. package/skills/trtc-ai-service/auto_adapters/node-backend/koa.js.tpl +31 -0
  87. package/skills/trtc-ai-service/auto_adapters/node-backend/manifest.yaml +47 -0
  88. package/skills/trtc-ai-service/auto_adapters/python-backend/README.md +22 -0
  89. package/skills/trtc-ai-service/auto_adapters/python-backend/django.py.tpl +32 -0
  90. package/skills/trtc-ai-service/auto_adapters/python-backend/fastapi.py.tpl +35 -0
  91. package/skills/trtc-ai-service/auto_adapters/python-backend/flask.py.tpl +31 -0
  92. package/skills/trtc-ai-service/auto_adapters/python-backend/manifest.yaml +45 -0
  93. package/skills/trtc-ai-service/capabilities/__init__.py +43 -0
  94. package/skills/trtc-ai-service/capabilities/conversation-core/.env.example +29 -0
  95. package/skills/trtc-ai-service/capabilities/conversation-core/INTEGRATION.md +134 -0
  96. package/skills/trtc-ai-service/capabilities/conversation-core/INTERFACE_ADAPT.md +111 -0
  97. package/skills/trtc-ai-service/capabilities/conversation-core/QUICK_START.md +62 -0
  98. package/skills/trtc-ai-service/capabilities/conversation-core/manifest.yaml +250 -0
  99. package/skills/trtc-ai-service/capabilities/conversation-core/requirements.txt +6 -0
  100. package/skills/trtc-ai-service/capabilities/conversation-core/src/__init__.py +10 -0
  101. package/skills/trtc-ai-service/capabilities/conversation-core/src/_capability_loader.py +218 -0
  102. package/skills/trtc-ai-service/capabilities/conversation-core/src/agent.py +231 -0
  103. package/skills/trtc-ai-service/capabilities/conversation-core/src/credentials.py +132 -0
  104. package/skills/trtc-ai-service/capabilities/conversation-core/src/health.py +355 -0
  105. package/skills/trtc-ai-service/capabilities/conversation-core/src/log_filter.py +76 -0
  106. package/skills/trtc-ai-service/capabilities/conversation-core/src/modality.py +109 -0
  107. package/skills/trtc-ai-service/capabilities/conversation-core/src/server.py +312 -0
  108. package/skills/trtc-ai-service/capabilities/conversation-core/src/trtc_client.py +315 -0
  109. package/skills/trtc-ai-service/capabilities/conversation-core/src/usersig.py +90 -0
  110. package/skills/trtc-ai-service/capabilities/conversation-core/tests/test_skeleton.py +216 -0
  111. package/skills/trtc-ai-service/capabilities/conversation-core/web-demo/README.md +48 -0
  112. package/skills/trtc-ai-service/capabilities/conversation-core/web-demo/app.js +415 -0
  113. package/skills/trtc-ai-service/capabilities/conversation-core/web-demo/index.html +68 -0
  114. package/skills/trtc-ai-service/capabilities/conversation-core/web-demo/styles.css +136 -0
  115. package/skills/trtc-ai-service/capabilities/digital-human/README.md +31 -0
  116. package/skills/trtc-ai-service/capabilities/digital-human/manifest.yaml +64 -0
  117. package/skills/trtc-ai-service/capabilities/digital-human/src/__init__.py +2 -0
  118. package/skills/trtc-ai-service/capabilities/digital-human/src/router.py +43 -0
  119. package/skills/trtc-ai-service/capabilities/human-handoff/INTERFACE_ADAPT.md +353 -0
  120. package/skills/trtc-ai-service/capabilities/human-handoff/README.md +44 -0
  121. package/skills/trtc-ai-service/capabilities/human-handoff/manifest.yaml +227 -0
  122. package/skills/trtc-ai-service/capabilities/human-handoff/src/__init__.py +2 -0
  123. package/skills/trtc-ai-service/capabilities/human-handoff/src/adapters/__init__.py +9 -0
  124. package/skills/trtc-ai-service/capabilities/human-handoff/src/adapters/default_rest.py +242 -0
  125. package/skills/trtc-ai-service/capabilities/human-handoff/src/adapters/factory.py +89 -0
  126. package/skills/trtc-ai-service/capabilities/human-handoff/src/adapters/local_queue.py +258 -0
  127. package/skills/trtc-ai-service/capabilities/human-handoff/src/adapters/mock.py +132 -0
  128. package/skills/trtc-ai-service/capabilities/human-handoff/src/core/__init__.py +25 -0
  129. package/skills/trtc-ai-service/capabilities/human-handoff/src/core/intent_detector.py +75 -0
  130. package/skills/trtc-ai-service/capabilities/human-handoff/src/core/models.py +163 -0
  131. package/skills/trtc-ai-service/capabilities/human-handoff/src/core/service.py +192 -0
  132. package/skills/trtc-ai-service/capabilities/human-handoff/src/feedback_store.py +54 -0
  133. package/skills/trtc-ai-service/capabilities/human-handoff/src/ports/__init__.py +4 -0
  134. package/skills/trtc-ai-service/capabilities/human-handoff/src/ports/handoff_client.py +86 -0
  135. package/skills/trtc-ai-service/capabilities/human-handoff/src/queue.py +62 -0
  136. package/skills/trtc-ai-service/capabilities/human-handoff/src/router.py +201 -0
  137. package/skills/trtc-ai-service/capabilities/human-handoff/src/summary_link.py +77 -0
  138. package/skills/trtc-ai-service/capabilities/human-handoff/src/trigger.py +25 -0
  139. package/skills/trtc-ai-service/capabilities/knowledge-base/INTERFACE_ADAPT.md +297 -0
  140. package/skills/trtc-ai-service/capabilities/knowledge-base/README.md +51 -0
  141. package/skills/trtc-ai-service/capabilities/knowledge-base/data/faq.json +20 -0
  142. package/skills/trtc-ai-service/capabilities/knowledge-base/manifest.yaml +211 -0
  143. package/skills/trtc-ai-service/capabilities/knowledge-base/src/__init__.py +8 -0
  144. package/skills/trtc-ai-service/capabilities/knowledge-base/src/adapters/__init__.py +9 -0
  145. package/skills/trtc-ai-service/capabilities/knowledge-base/src/adapters/default_rest.py +209 -0
  146. package/skills/trtc-ai-service/capabilities/knowledge-base/src/adapters/factory.py +86 -0
  147. package/skills/trtc-ai-service/capabilities/knowledge-base/src/adapters/local_json.py +172 -0
  148. package/skills/trtc-ai-service/capabilities/knowledge-base/src/adapters/mock.py +91 -0
  149. package/skills/trtc-ai-service/capabilities/knowledge-base/src/core/__init__.py +12 -0
  150. package/skills/trtc-ai-service/capabilities/knowledge-base/src/core/models.py +77 -0
  151. package/skills/trtc-ai-service/capabilities/knowledge-base/src/core/scoring.py +73 -0
  152. package/skills/trtc-ai-service/capabilities/knowledge-base/src/core/service.py +78 -0
  153. package/skills/trtc-ai-service/capabilities/knowledge-base/src/ports/__init__.py +4 -0
  154. package/skills/trtc-ai-service/capabilities/knowledge-base/src/ports/kb_client.py +61 -0
  155. package/skills/trtc-ai-service/capabilities/knowledge-base/src/retriever.py +56 -0
  156. package/skills/trtc-ai-service/capabilities/knowledge-base/src/router.py +85 -0
  157. package/skills/trtc-ai-service/capabilities/session-summary/INTERFACE_ADAPT.md +99 -0
  158. package/skills/trtc-ai-service/capabilities/session-summary/README.md +47 -0
  159. package/skills/trtc-ai-service/capabilities/session-summary/data/test_session.json +18 -0
  160. package/skills/trtc-ai-service/capabilities/session-summary/manifest.yaml +165 -0
  161. package/skills/trtc-ai-service/capabilities/session-summary/src/__init__.py +2 -0
  162. package/skills/trtc-ai-service/capabilities/session-summary/src/adapters/__init__.py +5 -0
  163. package/skills/trtc-ai-service/capabilities/session-summary/src/adapters/base.py +31 -0
  164. package/skills/trtc-ai-service/capabilities/session-summary/src/adapters/default_rest.py +67 -0
  165. package/skills/trtc-ai-service/capabilities/session-summary/src/adapters/factory.py +51 -0
  166. package/skills/trtc-ai-service/capabilities/session-summary/src/adapters/local_json.py +42 -0
  167. package/skills/trtc-ai-service/capabilities/session-summary/src/adapters/mock.py +22 -0
  168. package/skills/trtc-ai-service/capabilities/session-summary/src/recorder.py +210 -0
  169. package/skills/trtc-ai-service/capabilities/session-summary/src/router.py +93 -0
  170. package/skills/trtc-ai-service/capabilities/session-summary/src/summarizer.py +163 -0
  171. package/skills/trtc-ai-service/capabilities/tool-calling/INTERFACE_ADAPT.md +158 -0
  172. package/skills/trtc-ai-service/capabilities/tool-calling/README.md +50 -0
  173. package/skills/trtc-ai-service/capabilities/tool-calling/data/tools.yaml +58 -0
  174. package/skills/trtc-ai-service/capabilities/tool-calling/examples/__init__.py +1 -0
  175. package/skills/trtc-ai-service/capabilities/tool-calling/examples/local_tools.py +101 -0
  176. package/skills/trtc-ai-service/capabilities/tool-calling/manifest.yaml +146 -0
  177. package/skills/trtc-ai-service/capabilities/tool-calling/src/__init__.py +8 -0
  178. package/skills/trtc-ai-service/capabilities/tool-calling/src/dispatcher.py +54 -0
  179. package/skills/trtc-ai-service/capabilities/tool-calling/src/registry.py +219 -0
  180. package/skills/trtc-ai-service/capabilities/tool-calling/src/router.py +50 -0
  181. package/skills/trtc-ai-service/references/business-contract-spec.md +263 -0
  182. package/skills/trtc-ai-service/scenarios/custom-builder/README.md +86 -0
  183. package/skills/trtc-ai-service/scenarios/custom-builder/output-templates/recipe.yaml.j2 +194 -0
  184. package/skills/trtc-ai-service/scenarios/custom-builder/prompts/q1-business-scenario.md +43 -0
  185. package/skills/trtc-ai-service/scenarios/custom-builder/prompts/q2-io-modality.md +57 -0
  186. package/skills/trtc-ai-service/scenarios/custom-builder/prompts/q3-ui-form.md +55 -0
  187. package/skills/trtc-ai-service/scenarios/custom-builder/prompts/q4-capabilities.md +78 -0
  188. package/skills/trtc-ai-service/scenarios/customer-service/README.md +114 -0
  189. package/skills/trtc-ai-service/scenarios/customer-service/recipe.yaml +154 -0
  190. package/skills/trtc-ai-service/scenarios/customer-service/sample-data/README.md +32 -0
  191. package/skills/trtc-ai-service/scenarios/customer-service/sample-data/faq-sample.json +37 -0
  192. package/skills/trtc-ai-service/scenarios/customer-service/system-prompt.template.md +94 -0
  193. package/skills/trtc-ai-service/scenarios/customer-service/ui/admin-board/app.js +347 -0
  194. package/skills/trtc-ai-service/scenarios/customer-service/ui/admin-board/index.html +125 -0
  195. package/skills/trtc-ai-service/scenarios/customer-service/ui/admin-board/styles.css +487 -0
  196. package/skills/trtc-ai-service/scenarios/customer-service/ui/admin-board/tokens.css +71 -0
  197. package/skills/trtc-ai-service/scenarios/customer-service/ui/design-system/DESIGN_GUIDELINES.md +370 -0
  198. package/skills/trtc-ai-service/scenarios/customer-service/ui/voice-customer-service/README.md +68 -0
  199. package/skills/trtc-ai-service/scenarios/customer-service/ui/voice-customer-service/app.js +1307 -0
  200. package/skills/trtc-ai-service/scenarios/customer-service/ui/voice-customer-service/data.js +40 -0
  201. package/skills/trtc-ai-service/scenarios/customer-service/ui/voice-customer-service/index.html +233 -0
  202. package/skills/trtc-ai-service/scenarios/customer-service/ui/voice-customer-service/mock-shop.json +21 -0
  203. package/skills/trtc-ai-service/scenarios/customer-service/ui/voice-customer-service/styles.css +603 -0
  204. package/skills/trtc-ai-service/scenarios/customer-service/ui/voice-customer-service/tokens.css +71 -0
  205. package/skills/trtc-ai-service/scenarios/customer-service/ui/widget-floating/agent-link.js +323 -0
  206. package/skills/trtc-ai-service/scenarios/customer-service/ui/widget-floating/app.js +458 -0
  207. package/skills/trtc-ai-service/scenarios/customer-service/ui/widget-floating/index.html +109 -0
  208. package/skills/trtc-ai-service/scenarios/customer-service/ui/widget-floating/styles.css +489 -0
  209. package/skills/trtc-ai-service/scenarios/customer-service/ui/widget-floating/tokens.css +59 -0
  210. package/skills/trtc-ai-service/scripts/add-capability.py +364 -0
  211. package/skills/trtc-ai-service/scripts/contract-adapt.py +334 -0
  212. package/skills/trtc-ai-service/scripts/detect-stack.py +40 -0
  213. package/skills/trtc-ai-service/scripts/lib/__init__.py +20 -0
  214. package/skills/trtc-ai-service/scripts/lib/adapter_codegen.py +509 -0
  215. package/skills/trtc-ai-service/scripts/lib/arbitrator.py +152 -0
  216. package/skills/trtc-ai-service/scripts/lib/contract_resolver.py +519 -0
  217. package/skills/trtc-ai-service/scripts/lib/credential_validators.py +253 -0
  218. package/skills/trtc-ai-service/scripts/lib/curl_parser.py +303 -0
  219. package/skills/trtc-ai-service/scripts/lib/degrader.py +140 -0
  220. package/skills/trtc-ai-service/scripts/lib/injector.py +347 -0
  221. package/skills/trtc-ai-service/scripts/lib/manifest_resolver.py +288 -0
  222. package/skills/trtc-ai-service/scripts/lib/openapi_parser.py +289 -0
  223. package/skills/trtc-ai-service/scripts/lib/stack_detector.py +159 -0
  224. package/skills/trtc-ai-service/scripts/lib/tokens_compile.py +204 -0
  225. package/skills/trtc-ai-service/scripts/post-install-patch.py +225 -0
  226. package/skills/trtc-ai-service/scripts/setup-credentials.py +393 -0
  227. package/skills/trtc-ai-service/scripts/verify-credentials.py +108 -0
  228. package/skills/trtc-ai-service/start.sh +111 -0
  229. package/skills/trtc-ai-service/tests/__init__.py +1 -0
  230. package/skills/trtc-ai-service/tests/test_arbitrator.py +64 -0
  231. package/skills/trtc-ai-service/tests/test_capability_overlay.py +85 -0
  232. package/skills/trtc-ai-service/tests/test_contract_resolver.py +190 -0
  233. package/skills/trtc-ai-service/tests/test_handoff_ports.py +195 -0
  234. package/skills/trtc-ai-service/tests/test_kb_ports.py +195 -0
  235. package/skills/trtc-ai-service/tests/test_manifest_resolver.py +95 -0
  236. package/skills/trtc-ai-service/tests/test_recipe_assembly.py +175 -0
  237. package/skills/trtc-ai-service/tests/test_stack_and_degrader.py +101 -0
  238. package/skills/trtc-ai-service/tests/test_verify_credentials.py +285 -0
  239. package/skills/trtc-ai-service/triggers.yaml +29 -0
  240. package/skills/trtc-conference/SKILL.md +324 -0
  241. package/skills/trtc-conference/flows/onboarding.md +205 -0
  242. package/skills/trtc-conference/flows/topic.md +474 -0
  243. package/skills/trtc-conference/flows/troubleshoot.md +85 -0
  244. package/skills/trtc-conference/hooks/pretooluse_require_business_decisions.py +213 -0
  245. package/skills/trtc-conference/playbooks/medical-quickstart.md +84 -0
  246. package/skills/trtc-conference/playbooks/official-roomkit.md +97 -0
  247. package/skills/trtc-conference/references/local-usersig/basic-info-config.ts +39 -0
  248. package/skills/trtc-conference/references/usersig-handling.md +134 -0
  249. package/skills/trtc-conference/templates/medical-consultation/src/config/lib-generate-test-usersig-es.min.d.ts +4 -0
  250. package/skills/trtc-conference/templates/medical-consultation/src/config/lib-generate-test-usersig-es.min.js +2 -0
  251. package/skills/trtc-conference/tests/__pycache__/test_conference_onboarding_contract.cpython-313-pytest-9.0.2.pyc +0 -0
  252. package/skills/trtc-conference/tests/__pycache__/test_conference_topic_flow_contract.cpython-313-pytest-9.0.2.pyc +0 -0
  253. package/skills/trtc-conference/tests/test_conference_index_contract.py +43 -0
  254. package/skills/trtc-conference/tests/test_conference_onboarding_contract.py +103 -0
  255. package/skills/trtc-conference/tests/test_conference_template_contract.py +25 -0
  256. package/skills/trtc-conference/tests/test_conference_topic_flow_contract.py +132 -0
  257. package/skills/trtc-conference/tools/apply_checks.py +328 -0
  258. package/skills/trtc-conference/verify_lib/__init__.py +0 -0
  259. package/skills/{trtc-apply/guardrails/apply_lib → trtc-conference/verify_lib}/rule_parser.py +1 -1
  260. package/skills/trtc-docs/SKILL.md +91 -119
  261. package/.cursor/rules/ui-mode.mdc +0 -92
  262. package/ai-instructions/base.md +0 -13
  263. package/ai-instructions/ui-mode.md +0 -86
  264. package/knowledge-base/index.yaml +0 -454
  265. package/skills/trtc/room-builder/SKILL.md +0 -138
  266. package/skills/trtc/room-builder/templates/scenarios/medical-consultation/README.md +0 -108
  267. package/skills/trtc/room-builder/tools/render_ai_instructions.py +0 -226
  268. package/skills/trtc-apply/SKILL.md +0 -97
  269. package/skills/trtc-onboarding/SKILL.md +0 -839
  270. package/skills/trtc-onboarding/reference/path-a1-demo.md +0 -103
  271. package/skills/trtc-onboarding/reference/path-a2-integrate.md +0 -693
  272. package/skills/trtc-onboarding/reference/path-b-troubleshoot.md +0 -115
  273. package/skills/trtc-onboarding/reference/path-c-expand.md +0 -43
  274. package/skills/trtc-onboarding/reference/supported-matrix.md +0 -100
  275. package/skills/trtc-onboarding/reference/usersig-handling.md +0 -140
  276. package/skills/trtc-search/SKILL.md +0 -221
  277. package/skills/trtc-topic/SKILL.md +0 -638
  278. package/skills/trtc-topic/scripts/apply.py +0 -581
  279. package/skills/trtc-topic/scripts/lib/state_machine.py +0 -328
  280. package/skills/trtc-topic/tests/README.md +0 -70
  281. package/skills/trtc-topic/tests/conftest.py +0 -72
  282. package/skills/trtc-topic/tests/test_apply_cli.py +0 -480
  283. package/skills/trtc-topic/tests/test_end_to_end.py +0 -305
  284. package/skills/trtc-topic/tests/test_finalize_session.py +0 -51
  285. package/skills/trtc-topic/tests/test_gates.py +0 -316
  286. package/skills/trtc-topic/tests/test_session_resolver.py +0 -260
  287. package/skills/trtc-topic/tests/test_state_machine.py +0 -414
  288. package/skills/trtc-topic/tests/test_stop_require_apply.py +0 -99
  289. package/skills/trtc-topic/tests/test_topic_skill_invariants.py +0 -130
  290. /package/skills/{trtc-topic → trtc}/runtime/lib/platforms.py +0 -0
  291. /package/skills/{trtc-topic → trtc}/runtime/telemetry_collector.py +0 -0
  292. /package/skills/{trtc-topic/scripts → trtc/tools}/finalize_session.py +0 -0
  293. /package/skills/{trtc-apply/guardrails/apply_lib → trtc-ai-service/capabilities/conversation-core/tests}/__init__.py +0 -0
  294. /package/skills/{trtc-topic → trtc-conference}/references/execution-units.yaml +0 -0
  295. /package/skills/{trtc/room-builder/templates/scenarios/medical-consultation/src/config → trtc-conference/references/local-usersig}/lib-generate-test-usersig-es.min.d.ts +0 -0
  296. /package/skills/{trtc/room-builder/templates/scenarios/medical-consultation/src/config → trtc-conference/references/local-usersig}/lib-generate-test-usersig-es.min.js +0 -0
  297. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/docs/backend-contract.zh-CN.md +0 -0
  298. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/docs/integration.zh-CN.md +0 -0
  299. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/docs/theme.zh-CN.md +0 -0
  300. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/index.html +0 -0
  301. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/package.json +0 -0
  302. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/postcss.config.js +0 -0
  303. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/App.vue +0 -0
  304. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/components/ConsultationManagePanel.vue +0 -0
  305. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/components/LanguageSwitch.vue +0 -0
  306. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/components/LoadingSpinner.vue +0 -0
  307. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/components/MedicalAlert.vue +0 -0
  308. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/components/MedicalBusinessPanel.vue +0 -0
  309. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/components/MedicalButton.vue +0 -0
  310. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/components/MedicalConfirmDialog.vue +0 -0
  311. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/components/MedicalDataPanel.vue +0 -0
  312. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/components/MedicalRecordPanel.vue +0 -0
  313. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/components/PrescriptionPanel.vue +0 -0
  314. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/config/basic-info-config.ts +0 -0
  315. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/config/runtime-config.ts +0 -0
  316. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/env.d.ts +0 -0
  317. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/features/consultation/components/ConsultationChatPanel.vue +0 -0
  318. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/features/consultation/components/ConsultationMembersPanel.vue +0 -0
  319. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/features/consultation/components/ConsultationTranscriptionPanel.vue +0 -0
  320. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/features/consultation/components/ConsultationVideoStage.vue +0 -0
  321. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/features/consultation/components/InviteDoctorDialog.vue +0 -0
  322. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/features/consultation/components/KickMemberConfirmDialog.vue +0 -0
  323. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/features/consultation/types.ts +0 -0
  324. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/features/consultation/useConsultationChat.ts +0 -0
  325. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/features/consultation/useConsultationDevices.ts +0 -0
  326. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/features/consultation/useConsultationParticipants.ts +0 -0
  327. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/features/consultation/useConsultationPermissions.ts +0 -0
  328. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/features/consultation/utils.ts +0 -0
  329. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/i18n/en-US/index.ts +0 -0
  330. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/i18n/index.ts +0 -0
  331. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/i18n/medicalTranslate.ts +0 -0
  332. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/i18n/state.ts +0 -0
  333. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/i18n/zh-CN/index.ts +0 -0
  334. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/main.ts +0 -0
  335. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/mock/appointments.ts +0 -0
  336. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/mock/users.ts +0 -0
  337. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/router/index.ts +0 -0
  338. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/services/adapters/index.ts +0 -0
  339. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/services/adapters/integration/appointmentService.ts +0 -0
  340. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/services/adapters/integration/authService.ts +0 -0
  341. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/services/adapters/integration/launchContext.ts +0 -0
  342. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/services/adapters/integration/userService.ts +0 -0
  343. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/services/adapters/mock/appointmentService.ts +0 -0
  344. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/services/adapters/mock/authService.ts +0 -0
  345. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/services/adapters/mock/userService.ts +0 -0
  346. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/services/adapters/types.ts +0 -0
  347. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/shared/icons.ts +0 -0
  348. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/styles/index.css +0 -0
  349. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/styles/tailwind.css +0 -0
  350. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/styles/theme.css +0 -0
  351. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/utils/auth.ts +0 -0
  352. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/utils/format.ts +0 -0
  353. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/utils/navigation.ts +0 -0
  354. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/utils/session.ts +0 -0
  355. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/views/DoctorConsultationView.vue +0 -0
  356. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/views/DoctorDashboardView.vue +0 -0
  357. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/views/LoginView.vue +0 -0
  358. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/views/PatientConsultationFinishedView.vue +0 -0
  359. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/views/PatientConsultationView.vue +0 -0
  360. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/views/PatientSelectDoctorView.vue +0 -0
  361. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/src/views/PatientWaitingView.vue +0 -0
  362. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/tsconfig.json +0 -0
  363. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/tsconfig.node.json +0 -0
  364. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation/vite.config.ts +0 -0
  365. /package/skills/{trtc/room-builder/templates/scenarios → trtc-conference/templates}/medical-consultation//346/216/245/345/205/245/350/257/264/346/230/216.md" +0 -0
  366. /package/skills/{trtc-topic/runtime/lib → trtc-conference/tools}/__init__.py +0 -0
@@ -1,486 +1,2526 @@
1
- # TRTC 原子能力(Slice)定义规范
1
+ # TRTC 原子能力(Slice)定义规范
2
+ # TRTC 原子能力(Slice)定义规范
2
3
 
3
4
  > 本文档定义了 TRTC AI 知识库中 Slice 的拆分标准、编写规范和规划方法论。
4
5
  > 所有 slice 的创建和维护都应遵循本规范。
5
6
 
6
7
  ---
7
8
 
9
+ ## 0. 给新人:你只需要做三件事
10
+
11
+ 如果你是第一次写 slice,只要:
12
+
13
+ 1. **复制模板**:找到对应 section 的「写作模板」,把 `{占位符}` 全部填掉。
14
+ 2. **对照正反例**:每个 section 都有 ✅ 正例 + ❌ 反例,写完后逐条对照自查。
15
+ 3. **跑验证手段**:每个 `[必填]` 都附了「验证手段」,跑命令通过才算合格。
16
+
17
+ **只要这三步通过,你的 slice 就自动符合团队的 AI 文档质量标准。**
18
+
19
+ > ⚠️ 这份 spec 里你看到的所有"强势语言"("绝不要""必须""不可合并")**不是夸张表达**——都对应过真实事故。
20
+
21
+ ---
22
+
23
+ ## 0. 给新人:你只需要做三件事
24
+
25
+ 如果你是第一次写 slice,只要:
26
+
27
+ 1. **复制模板**:找到对应 section 的「写作模板」,把 `{占位符}` 全部填掉。
28
+ 2. **对照正反例**:每个 section 都有 ✅ 正例 + ❌ 反例,写完后逐条对照自查。
29
+ 3. **跑验证手段**:每个 `[必填]` 都附了「验证手段」,跑命令通过才算合格。
30
+
31
+ **只要这三步通过,你的 slice 就自动符合团队的 AI 文档质量标准。**
32
+
33
+ > ⚠️ 这份 spec 里你看到的所有"强势语言"("绝不要""必须""不可合并")**不是夸张表达**——都对应过真实事故。
34
+
35
+ ---
36
+
8
37
  ## 一、什么是 Slice
9
38
 
10
- Slice(原子能力)是 TRTC AI 知识库的最小知识单元。每个 slice 描述一个**独立的功能点**,包含:这个功能是什么、怎么用、常见的坑、出了问题怎么排查。
39
+ Slice(原子能力)是 TRTC AI 知识库的最小知识单元。每个 slice 描述一个**独立的功能点**,包含:这个功能是什么、怎么用、常见的坑、出了问题怎么排查。
40
+ Slice(原子能力)是 TRTC AI 知识库的最小知识单元。每个 slice 描述一个**独立的功能点**,包含:这个功能是什么、怎么用、常见的坑、出了问题怎么排查。
41
+
42
+ **类比**:如果 TRTC SDK 是一台车,slice 就是驾驶手册里的一个章节——"怎么启动"、"怎么倒车"、"怎么用定速巡航",每一章独立可读,合在一起就是完整手册。
43
+
44
+ **最终读者是 AI**:slice 文档会被 AI 直接读取并用于生成代码。这意味着:
45
+ - 任何模糊词("应该""大概""一般来说")都会被 AI 解释为"可选" → 跳过
46
+ - 任何遗漏的反例,AI 都会用训练数据里的错误模式去补
47
+ - 任何不可机械验证的规则,AI 都可能"凑字符串"通过
48
+
49
+ → 所以本 spec 用极端强势的语言,是为了让产出的 slice 也具有同样的硬约束力。
50
+ **类比**:如果 TRTC SDK 是一台车,slice 就是驾驶手册里的一个章节——"怎么启动"、"怎么倒车"、"怎么用定速巡航",每一章独立可读,合在一起就是完整手册。
51
+
52
+ **最终读者是 AI**:slice 文档会被 AI 直接读取并用于生成代码。这意味着:
53
+ - 任何模糊词("应该""大概""一般来说")都会被 AI 解释为"可选" → 跳过
54
+ - 任何遗漏的反例,AI 都会用训练数据里的错误模式去补
55
+ - 任何不可机械验证的规则,AI 都可能"凑字符串"通过
56
+
57
+ → 所以本 spec 用极端强势的语言,是为了让产出的 slice 也具有同样的硬约束力。
58
+
59
+ ---
60
+
61
+ ## 二、Slice 拆分标准
62
+
63
+ ### 强制拆分判断流程(任何一步不可跳过)
64
+
65
+ 新建 slice 前,**必须**按顺序回答以下 4 个问题。任何一个问题答不出 → 不允许新建 slice。
66
+
67
+ #### 问题 1:能不能一次讲清楚?
68
+
69
+ **判断标准**:在 PR 描述中粘贴一份 ≤500 字的"客户问这个问题时的一次性回答 demo"。
70
+ - 超过 500 字 → split,本 slice 太大
71
+ - 不到 50 字 → 太小,合并到相关 slice
72
+ - 恰好够讲清原理 + 关键 API + 常见错误码 → ✅ 合格粒度
73
+
74
+ ✅ **正例**:
75
+ - "多端登录老是互踢怎么办?" → 讲策略配置 + 回调处理 + 常见错误码,300 字搞定 ✅
76
+ - "消息发不出去" → 讲发送流程 + 权限检查 + 错误码,400 字搞定 ✅
77
+
78
+ ❌ **反例**:
79
+ - "消息功能怎么做?" → 发送+接收+历史+撤回+已读+推送... 至少 3000 字 ❌(太大,split)
80
+ - "怎么设置消息的优先级字段?" → 一句话回答,30 字 ❌(太小,合并到「发送消息」)
81
+
82
+ #### 问题 2:出问题时,排查方向一样吗?
83
+
84
+ **判断标准**:在最近 100 个 ticket 中搜这两类问题,如果它们的 assignee 通常不是同一人,或排查思路完全不同 → 拆。
85
+ ### 强制拆分判断流程(任何一步不可跳过)
86
+
87
+ 新建 slice 前,**必须**按顺序回答以下 4 个问题。任何一个问题答不出 → 不允许新建 slice。
88
+
89
+ #### 问题 1:能不能一次讲清楚?
90
+
91
+ **判断标准**:在 PR 描述中粘贴一份 ≤500 字的"客户问这个问题时的一次性回答 demo"。
92
+ - 超过 500 字 → split,本 slice 太大
93
+ - 不到 50 字 → 太小,合并到相关 slice
94
+ - 恰好够讲清原理 + 关键 API + 常见错误码 → ✅ 合格粒度
95
+
96
+ ✅ **正例**:
97
+ - "多端登录老是互踢怎么办?" → 讲策略配置 + 回调处理 + 常见错误码,300 字搞定 ✅
98
+ - "消息发不出去" → 讲发送流程 + 权限检查 + 错误码,400 字搞定 ✅
99
+
100
+ ❌ **反例**:
101
+ - "消息功能怎么做?" → 发送+接收+历史+撤回+已读+推送... 至少 3000 字 ❌(太大,split)
102
+ - "怎么设置消息的优先级字段?" → 一句话回答,30 字 ❌(太小,合并到「发送消息」)
103
+
104
+ #### 问题 2:出问题时,排查方向一样吗?
105
+
106
+ **判断标准**:在最近 100 个 ticket 中搜这两类问题,如果它们的 assignee 通常不是同一人,或排查思路完全不同 → 拆。
107
+
108
+ | 场景 | 排查方向 | 结论 |
109
+ |------|---------|------|
110
+ | "消息发不出去" vs "收不到消息" | 发送查网络/权限/格式;接收查监听/登录状态/群设置 | → **拆成两个** |
111
+ | "发文本消息" vs "发图片消息" | 都是查消息格式和网络 | → **合成一个**(发送消息) |
112
+ | "主播无法开播" vs "连麦布局不对" | 开播查权限/配置;布局查模板参数 | → **拆成两个** |
113
+ | "消息发不出去" vs "收不到消息" | 发送查网络/权限/格式;接收查监听/登录状态/群设置 | → **拆成两个** |
114
+ | "发文本消息" vs "发图片消息" | 都是查消息格式和网络 | → **合成一个**(发送消息) |
115
+ | "主播无法开播" vs "连麦布局不对" | 开播查权限/配置;布局查模板参数 | → **拆成两个** |
116
+
117
+ #### 问题 3:是独立的用户动作吗?
118
+ #### 问题 3:是独立的用户动作吗?
119
+
120
+ 一个 slice = 一个用户能感知到的**独立操作步骤**。
121
+ 一个 slice = 一个用户能感知到的**独立操作步骤**。
122
+
123
+ | 场景 | 用户动作 | 结论 |
124
+ |------|---------|------|
125
+ | 配置准备页 → 点开播 → 进入直播间 | 一个连贯动作 | → **一个** slice(主播开播) |
126
+ | 选择连麦布局模板 | 独立配置决策 | → **单独一个** slice |
127
+ | 隐藏按钮 + 改文案 + 换图标 | 都是"改 UI 外观" | → **合成一个** slice(UI 定制) |
128
+ | 配置准备页 → 点开播 → 进入直播间 | 一个连贯动作 | → **一个** slice(主播开播) |
129
+ | 选择连麦布局模板 | 独立配置决策 | → **单独一个** slice |
130
+ | 隐藏按钮 + 改文案 + 换图标 | 都是"改 UI 外观" | → **合成一个** slice(UI 定制) |
131
+
132
+ #### 问题 4:能被 ≥2 个场景复用吗?(强制门控)
133
+
134
+ **这是最常被忽略、也最致命的问题**。一个 slice 必须能被 **2 个及以上** scenario(或其他 slice)引用。
135
+
136
+ **强制证据要求**:
137
+ - [ ] 在 PR 描述中**列出至少 2 个具体 scenario id**
138
+ - [ ] 在 `index.yaml` 中能搜到这些 scenario 的引用关系
139
+ - [ ] 缺少 ≥2 引用 → **不允许合并**(除非走破例条款)
140
+ #### 问题 4:能被 ≥2 个场景复用吗?(强制门控)
141
+
142
+ **这是最常被忽略、也最致命的问题**。一个 slice 必须能被 **2 个及以上** scenario(或其他 slice)引用。
143
+
144
+ **强制证据要求**:
145
+ - [ ] 在 PR 描述中**列出至少 2 个具体 scenario id**
146
+ - [ ] 在 `index.yaml` 中能搜到这些 scenario 的引用关系
147
+ - [ ] 缺少 ≥2 引用 → **不允许合并**(除非走破例条款)
148
+
149
+ | 场景 | 复用性判断 | 结论 |
150
+ |------|----------|------|
151
+ | 「发送消息」 | 所有 Chat scenario 都用 | → **独立 slice** |
152
+ | 「进房」 | Live、Call、Room 共用 | → **独立 slice** |
153
+ | 「主播开播前的网络探测提示」 | 只在「主播开播」一个场景出现 | → **合并到 `live/anchor-lifecycle`** |
154
+ | 「发送消息」 | 所有 Chat scenario 都用 | → **独立 slice** |
155
+ | 「进房」 | Live、Call、Room 共用 | → **独立 slice** |
156
+ | 「主播开播前的网络探测提示」 | 只在「主播开播」一个场景出现 | → **合并到 `live/anchor-lifecycle`** |
157
+ | 「连麦申请时的倒计时 UI 定制」 | 只有「观众申请连麦」会用 | → **合并到 `live/coguest-apply`** |
158
+
159
+ **破例条款**(且仅当):能力本身**极度独立、概念自洽、边界清晰**(典型如「错误码速查」「日志诊断入口」)。
160
+ - 必须在 slice 开头**明文写清**:「当前仅 X 场景使用,预留给 Y、Z 场景」
161
+ - 缺少这段声明 → 视为未使用破例 → 拒绝合并
162
+
163
+ #### 必填项语义三件套(拆分判断)
164
+
165
+ - **违反后果**:跳过任何一个问题 → 产出孤儿 slice / 重复 slice / 粒度失衡 slice → 知识库治理债累积 → 半年后必须做大批量重构(历史教训:2025-Q1 清理孤儿 slice 花了 1 个月)
166
+ - **验证手段**:PR 描述中**逐条粘贴 4 个问题的回答**;reviewer 检查问题 4 的引用方是否真实存在于 `index.yaml`
167
+ - **绕过条件**:无。这是 slice 存在的合法性前提,不接受任何豁免
168
+
169
+ ---
170
+ **破例条款**(且仅当):能力本身**极度独立、概念自洽、边界清晰**(典型如「错误码速查」「日志诊断入口」)。
171
+ - 必须在 slice 开头**明文写清**:「当前仅 X 场景使用,预留给 Y、Z 场景」
172
+ - 缺少这段声明 → 视为未使用破例 → 拒绝合并
173
+
174
+ #### 必填项语义三件套(拆分判断)
175
+
176
+ - **违反后果**:跳过任何一个问题 → 产出孤儿 slice / 重复 slice / 粒度失衡 slice → 知识库治理债累积 → 半年后必须做大批量重构(历史教训:2025-Q1 清理孤儿 slice 花了 1 个月)
177
+ - **验证手段**:PR 描述中**逐条粘贴 4 个问题的回答**;reviewer 检查问题 4 的引用方是否真实存在于 `index.yaml`
178
+ - **绕过条件**:无。这是 slice 存在的合法性前提,不接受任何豁免
179
+
180
+ ---
181
+
182
+ ### 粒度对比示例
183
+
184
+ 以「消息」为例:
185
+ 以「消息」为例:
186
+
187
+ ```
188
+ ❌ 太粗 → 一个 "消息" slice 包含发送+接收+历史+撤回+转发+已读+推送
189
+ 后果:客户说"消息收不到",AI 要在几千字里找,80% 概率找错段落
190
+ ❌ 太粗 → 一个 "消息" slice 包含发送+接收+历史+撤回+转发+已读+推送
191
+ 后果:客户说"消息收不到",AI 要在几千字里找,80% 概率找错段落
192
+
193
+ ❌ 太细 → 把发文本、发图片、发视频、发文件各做一个 slice
194
+ 后果:用法和排障几乎一样,AI 学到 4 份重复内容,生成代码时随机选
195
+ ❌ 太细 → 把发文本、发图片、发视频、发文件各做一个 slice
196
+ 后果:用法和排障几乎一样,AI 学到 4 份重复内容,生成代码时随机选
197
+
198
+ ✅ 合适 → 拆成:发送消息 / 接收消息 / 历史消息 / 消息撤回 / 离线推送
199
+ 每个都能一次讲清,排查方向各不相同
200
+ ✅ 合适 → 拆成:发送消息 / 接收消息 / 历史消息 / 消息撤回 / 离线推送
201
+ 每个都能一次讲清,排查方向各不相同
202
+ ```
203
+
204
+ ---
205
+
206
+ ## 三、Slice 两层架构:主线 + 反馈
207
+ ## 三、Slice 两层架构:主线 + 反馈
208
+
209
+ | 层级 | 名称 | 来源 | 用途 |
210
+ |------|------|------|------|
211
+ | 🅰️ **主线 Slice** | 骨架 | 按 SDK 能力域系统规划(来自官方文档+研发经验) | 保证每个核心功能都有覆盖 |
212
+ | 🅰️ **主线 Slice** | 骨架 | 按 SDK 能力域系统规划(来自官方文档+研发经验) | 保证每个核心功能都有覆盖 |
213
+ | 🅱️ **反馈 Slice** | 血肉 | 从产品/销售收集的用户高频问题中提炼 | 补充真实的坑和边缘场景 |
214
+
215
+ ### 两者的关系
216
+ - **主线是骨架**:每个开发者都要走的路(初始化 → 登录 → 发消息 → ...)
217
+ - **反馈是血肉**:开发者最容易摔跤的坑(互踢死循环、推送不到达、...)
218
+ - 反馈 slice 可以是主线 slice 的深度补充,也可以是全新的边缘场景
219
+ - **主线是骨架**:每个开发者都要走的路(初始化 → 登录 → 发消息 → ...)
220
+ - **反馈是血肉**:开发者最容易摔跤的坑(互踢死循环、推送不到达、...)
221
+ - 反馈 slice 可以是主线 slice 的深度补充,也可以是全新的边缘场景
222
+
223
+ ### 在 per-product platform index 中的标记
224
+
225
+ ```yaml
226
+ - id: chat/multi-instance
227
+ name: 多端登录与互踢
228
+ tags: [multi-instance, kick-offline, login]
229
+ platforms: [web, android, ios, flutter]
230
+ file: slices/chat/multi-instance.md
231
+ description: 多端登录策略配置、互踢回调处理、常见错误码
232
+ status: active # active | planned
233
+ ```
234
+
235
+ ---
236
+
237
+ ## 四、Slice 文件结构规范
238
+
239
+ 每个 slice 文件是 Markdown 文件,包含 YAML frontmatter 和固定的内容结构。
240
+ 每个 slice 文件是 Markdown 文件,包含 YAML frontmatter 和固定的内容结构。
241
+
242
+ ### 文件位置
243
+
244
+ ```
245
+ knowledge-base/slices/{product}/{ability}.md # 产品级概览(跨平台通用)
246
+ knowledge-base/slices/{product}/{ability}.md # 产品级概览(跨平台通用)
247
+ knowledge-base/slices/{product}/{platform}/{ability}.md # 平台实现细节
248
+ ```
249
+
250
+ > **平台实现文件模板**:新建平台 slice 时,请复制 [`platform-slice-template.md`](platform-slice-template.md) 并按批注填写。填写范例见 `slices/live/ios/coguest-apply.md`。
251
+ > **平台实现文件模板**:新建平台 slice 时,请复制 [`platform-slice-template.md`](platform-slice-template.md) 并按批注填写。填写范例见 `slices/live/ios/coguest-apply.md`。
252
+
253
+ ### Section 标签约定
254
+
255
+ 每个 section 标题后面统一标注三种标签之一:
256
+ 每个 section 标题后面统一标注三种标签之一:
257
+
258
+ | 标签 | 含义 | 省略规则 |
259
+ |------|------|---------|
260
+ | `[必填]` | 必须写,否则 slice 不合格 | 不可省 |
261
+ | `[可选]` | 视情况写,不影响合格 | 可整段删除 |
262
+ | `[条件必填:<触发条件>]` | 满足条件时必须写 | 不满足时可整段删除 |
263
+ | `[必填]` | 必须写,否则 slice 不合格 | 不可省 |
264
+ | `[可选]` | 视情况写,不影响合格 | 可整段删除 |
265
+ | `[条件必填:<触发条件>]` | 满足条件时必须写 | 不满足时可整段删除 |
266
+
267
+ 示例:
268
+ 示例:
269
+ ```markdown
270
+ ## 功能说明 [必填]
271
+ ## 调用时序 [条件必填:异步回调嵌套 ≥3 层 或 涉及 3 个及以上角色]
272
+ ## 调用时序 [条件必填:异步回调嵌套 ≥3 层 或 涉及 3 个及以上角色]
273
+ ## 关联知识 [可选]
274
+ ```
275
+
276
+ ### Frontmatter 字段
277
+
278
+ ```yaml
279
+ ---
280
+ id: chat/msg-send # [必填] Slice ID,与对应的 per-product platform index 中的 id 一致
281
+ name: 发送消息 # [必填] Slice 名称
282
+ product: chat # [必填] 所属产品
283
+ tags: [message, send, ...] # [必填] 搜索标签,至少 3 个
284
+ tags: [message, send, ...] # [必填] 搜索标签,至少 3 个
285
+ platforms: [web, android, ios, flutter] # [必填] 支持的平台
286
+ related: # [可选] 关联的 slice
287
+ related: # [可选] 关联的 slice
288
+ - chat/msg-receive
289
+ - chat/msg-custom
290
+ ---
291
+ ```
292
+
293
+ > **官方文档链接统一放在平台实现文件的 `api_docs` 字段**,产品级概览不放文档链接——因为教程/指南页通常按平台区分。
294
+ > **官方文档链接统一放在平台实现文件的 `api_docs` 字段**,产品级概览不放文档链接——因为教程/指南页通常按平台区分。
295
+
296
+ #### 必填项语义三件套(Frontmatter)
297
+
298
+ - **违反后果**:字段缺失或与 index.yaml 不一致 → AI 路由到错误 slice / 找不到平台实现 → 用户报"找不到"bug → 维护者排查 1 小时定位到 frontmatter 错字
299
+ - **验证手段**:`python scripts/validate_frontmatter.py {file}`(检查必填字段齐全 + 与 index.yaml 一致)
300
+ - **绕过条件**:无
301
+
302
+ ---
303
+ #### 必填项语义三件套(Frontmatter)
304
+
305
+ - **违反后果**:字段缺失或与 index.yaml 不一致 → AI 路由到错误 slice / 找不到平台实现 → 用户报"找不到"bug → 维护者排查 1 小时定位到 frontmatter 错字
306
+ - **验证手段**:`python scripts/validate_frontmatter.py {file}`(检查必填字段齐全 + 与 index.yaml 一致)
307
+ - **绕过条件**:无
308
+
309
+ ---
310
+
311
+ ### 内容结构
312
+
313
+ #### 产品级概览(`{product}/{ability}.md`)
314
+ #### 产品级概览(`{product}/{ability}.md`)
315
+
316
+ 产品级概览是**跨平台通用**的,描述"做什么"和"为什么",不涉及"怎么做"。
317
+ 产品级概览是**跨平台通用**的,描述"做什么"和"为什么",不涉及"怎么做"。
318
+
319
+ ##### 平台无关性规则
320
+ ##### 平台无关性规则
321
+
322
+ | ✅ 可以出现 | ❌ 不可以出现 |
323
+ |-------------|-------------|
324
+ | 操作语义("观众发起连麦申请") | 具体 API 签名(`applyForSeat(seatIndex:timeout:)` 这种 Swift 命名参数风格) |
325
+ | 通用概念名("连麦管理器"、"事件流") | 平台特有类名/机制(`PassthroughSubject`、`ViewController`、`cancellable`) |
326
+ | 行为级最佳实践("通过前不要开设备") | 代码结构级约束("`[weak self]` 避免循环引用") |
327
+ | 通用排障逻辑("检查主播端是否订阅了事件") | 平台特有排障("检查 cancellable 是否被提前释放") |
328
+ | 操作语义("观众发起连麦申请") | 具体 API 签名(`applyForSeat(seatIndex:timeout:)` 这种 Swift 命名参数风格) |
329
+ | 通用概念名("连麦管理器"、"事件流") | 平台特有类名/机制(`PassthroughSubject`、`ViewController`、`cancellable`) |
330
+ | 行为级最佳实践("通过前不要开设备") | 代码结构级约束("`[weak self]` 避免循环引用") |
331
+ | 通用排障逻辑("检查主播端是否订阅了事件") | 平台特有排障("检查 cancellable 是否被提前释放") |
332
+ | 跨平台统一的错误码 | 仅某平台出现的错误码或异常行为 |
333
+
334
+ ##### 自查方法
335
+
336
+ 把文件中所有 API 名、类名、术语逐一过一遍——如果一个 Android 开发者读到它会觉得困惑或不适用,那就是平台特有内容,应下沉到平台文件。
337
+
338
+ ✅ **自查正例**(产品级概览):
339
+ > 「观众通过『连麦管理器』调用申请操作,主播端通过『事件流』收到申请通知。申请超时由 SDK 内部计时器控制,默认 30 秒。」
340
+ - 用了通用概念名("连麦管理器""事件流"),iOS/Android/Web 开发者读了都能对应到自己的 API
341
+ - 默认值"30 秒"是跨平台一致的常量,可以写
342
+
343
+ ❌ **自查反例**(产品级概览混入平台细节):
344
+ > 「观众调用 `CoGuestStore.shared.applyForSeat(timeout:)`,主播端通过 `PassthroughSubject` 订阅 `applicationReceived` 事件,记得用 `[weak self]` 避免循环引用。」
345
+ - `CoGuestStore.shared.xxx` = Swift 单例语法,Android 开发者懵
346
+ - `PassthroughSubject` = Combine 框架特有,iOS 之外不存在
347
+ - `[weak self]` = Swift 内存管理,跨平台无意义
348
+ - → 整段下沉到 `live/ios/coguest-apply.md`
349
+
350
+ ##### 文件骨架
351
+ ##### 自查方法
352
+
353
+ 把文件中所有 API 名、类名、术语逐一过一遍——如果一个 Android 开发者读到它会觉得困惑或不适用,那就是平台特有内容,应下沉到平台文件。
354
+
355
+ ✅ **自查正例**(产品级概览):
356
+ > 「观众通过『连麦管理器』调用申请操作,主播端通过『事件流』收到申请通知。申请超时由 SDK 内部计时器控制,默认 30 秒。」
357
+ - 用了通用概念名("连麦管理器""事件流"),iOS/Android/Web 开发者读了都能对应到自己的 API
358
+ - 默认值"30 秒"是跨平台一致的常量,可以写
359
+
360
+ ❌ **自查反例**(产品级概览混入平台细节):
361
+ > 「观众调用 `CoGuestStore.shared.applyForSeat(timeout:)`,主播端通过 `PassthroughSubject` 订阅 `applicationReceived` 事件,记得用 `[weak self]` 避免循环引用。」
362
+ - `CoGuestStore.shared.xxx` = Swift 单例语法,Android 开发者懵
363
+ - `PassthroughSubject` = Combine 框架特有,iOS 之外不存在
364
+ - `[weak self]` = Swift 内存管理,跨平台无意义
365
+ - → 整段下沉到 `live/ios/coguest-apply.md`
366
+
367
+ ##### 文件骨架
368
+
369
+ ```markdown
370
+ # {名称}(产品级概览)
371
+ # {名称}(产品级概览)
372
+
373
+ ## 功能说明 [必填]
374
+ ## 核心概念 [必填]
375
+ ## 最佳实践 [必填]
376
+ ### ✅ ALWAYS(必须做的)
377
+ ### ❌ NEVER(绝不要做的)
378
+ ### ✅ ALWAYS(必须做的)
379
+ ### ❌ NEVER(绝不要做的)
380
+ ## 排障指南 [必填]
381
+ ### 常见错误码
382
+ ### 排障流程
383
+ ## 关联知识 [可选]
384
+ ```
385
+
386
+ 各 section 详细要求见下方。
387
+
388
+ ---
389
+
390
+ ##### 功能说明 [必填]
391
+
392
+ ###### 1️⃣ 你必须写什么
393
+ 一段 100-200 字的散文,回答三个问题:
394
+ - 这个能力解决什么问题(用客户的语言,不用 SDK 术语)
395
+ - 典型业务场景举 1-2 个
396
+ - 最低 SDK 版本要求(若有)
397
+
398
+ ###### 2️⃣ 写作模板
399
+ ```markdown
400
+ ## 功能说明
401
+
402
+ {能力名}解决 {具体业务问题}。典型场景包括 {场景 1}、{场景 2}。
403
+
404
+ 要求 SDK 版本 ≥ {version}。{若有跨平台版本差异,说明}。
405
+ ```
406
+
407
+ ###### 3️⃣ ✅ 正例(摘自 chat/multi-instance)
408
+ ```markdown
409
+ ## 功能说明
410
+
411
+ 多端登录指同一用户在多个设备(手机、平板、Web)同时登录 IM 账号的能力。
412
+ 解决的问题是:用户在手机上聊天,切换到电脑也能继续,不需要被强制踢下线。
413
+ 典型场景:企业 IM(电脑+手机同时在线)、客服系统(坐席多端备份)。
414
+
415
+ 要求 IM SDK ≥ 7.0,需要在控制台开通"多端登录"套餐(基础版不支持)。
416
+ ```
417
+
418
+ 为什么这是正例:
419
+ - ✅ 第一句用客户语言("同时登录")而非 SDK 术语("multi-instance")
420
+ - ✅ 写出了"解决什么问题",新人 30 秒能 get
421
+ - ✅ 给了 2 个具体场景,不是空洞的"很多场景"
422
+ - ✅ 标注了版本和套餐要求(常见踩坑点)
423
+
424
+ ###### 4️⃣ ❌ 反例
425
+ ```markdown
426
+ ## 功能说明
427
+
428
+ 本 slice 介绍 multi-instance 功能。该功能允许用户在多端登录,
429
+ 具体使用方式参见后续章节。
430
+ ```
431
+
432
+ 为什么这是反例:
433
+ - ❌ "本 slice 介绍" = 元描述,AI 拿不到任何业务信息
434
+ - ❌ "具体使用方式参见后续章节" = 偷懒,等于没写
435
+ - ❌ 没说解决什么问题、没场景、没版本要求
436
+ - → review 时直接打回
437
+
438
+ ###### 5️⃣ 必填项语义三件套
439
+ - **违反后果**:功能说明缺失或空洞 → AI 路由准确率下降 30%+(无法判断是否匹配用户意图)→ 客户问对了问题但被引到错误 slice
440
+ - **验证手段**:人工 review,逐条对照"三个问题"是否答全;字数 100-200 之间
441
+ - **绕过条件**:无
442
+
443
+ ---
444
+
445
+ ##### 核心概念 [必填]
446
+
447
+ ###### 1️⃣ 你必须写什么
448
+ 用**操作名 + 语义描述**列出该能力涉及的核心概念。不写平台特有 API 签名。
449
+ 若有状态机/角色关系,画出来。
450
+
451
+ ###### 2️⃣ 写作模板
452
+ ```markdown
453
+ ## 核心概念
454
+
455
+ ### 涉及角色
456
+ - **{角色 1}**:{这个角色做什么}
457
+ - **{角色 2}**:{这个角色做什么}
458
+
459
+ ### 关键操作
460
+ | 操作名 | 语义 | 触发方 |
461
+ |--------|------|--------|
462
+ | {操作 1} | {做了什么} | {谁触发} |
463
+ | {操作 2} | {做了什么} | {谁触发} |
464
+
465
+ ### 状态机(如有)
466
+ {状态 A} → [{触发事件}] → {状态 B} → [{事件}] → {状态 C}
467
+ ```
468
+
469
+ ###### 3️⃣ ✅ 正例(摘自 live/coguest-apply)
470
+ ```markdown
471
+ ## 核心概念
472
+
473
+ ### 涉及角色
474
+ - **观众(Audience)**:发起连麦申请的一方,等待主播同意后上麦
475
+ - **主播(Host)**:接收申请并决定是否同意的一方,有最终决策权
476
+
477
+ ### 关键操作
478
+ | 操作名 | 语义 | 触发方 |
479
+ |--------|------|--------|
480
+ | 申请连麦 | 观众请求加入主播的麦位,带超时(默认 30s) | 观众 |
481
+ | 同意申请 | 主播接受请求,观众变为连麦者 | 主播 |
482
+ | 拒绝申请 | 主播拒绝请求,观众回到观众态 | 主播 |
483
+ | 取消申请 | 观众主动撤回未处理的申请 | 观众 |
484
+
485
+ ### 状态机
486
+ 观众态 → [申请连麦] → 申请中 → [主播同意] → 连麦中
487
+ → [主播拒绝/超时] → 观众态
488
+ → [观众取消] → 观众态
489
+ ```
490
+
491
+ 为什么这是正例:
492
+ - ✅ 角色定义在最前,后续操作都基于角色
493
+ - ✅ 每个操作有"触发方"列,明确谁能做什么
494
+ - ✅ 状态机用纯文字+箭头,不依赖任何平台框架
495
+ - ✅ 整段没出现任何 Swift/Kotlin/JS 语法
496
+
497
+ ###### 4️⃣ ❌ 反例
498
+ ```markdown
499
+ ## 核心概念
500
+
501
+ 观众调用 `CoGuestStore.shared.applyForSeat(timeout: 30)` 发起申请,
502
+ 主播订阅 `applicationReceived` 事件接收。申请超时会触发 `.failure` 回调。
503
+ ```
504
+
505
+ 为什么这是反例:
506
+ - ❌ `CoGuestStore.shared.xxx` = iOS Swift 语法 → 平台特有
507
+ - ❌ `.failure` = Swift Result 类型 → 平台特有
508
+ - ❌ 没区分角色、没状态机
509
+ - → 应整段下沉到 `live/ios/coguest-apply.md`,产品级概览改写为操作语义
510
+
511
+ ###### 5️⃣ 必填项语义三件套
512
+ - **违反后果**:出现平台特有 API → 跨平台 AI 生成时混淆(Android 开发者拿到 iOS 代码)→ 编译报错投诉
513
+ - **验证手段**:人工 review,过一遍每个 backtick 内的标识符,任一是平台特有 → 打回
514
+ - **绕过条件**:无
515
+
516
+ ---
517
+
518
+ ##### 最佳实践 - ALWAYS [必填,至少 3 条]
519
+
520
+ ###### 1️⃣ 你必须写什么
521
+ 列出**行为级**的"必须做的事"。描述"该做什么",不指定"用哪个 API 做"。
522
+
523
+ ###### 2️⃣ 写作模板
524
+ ```markdown
525
+ ### ✅ ALWAYS
526
+
527
+ - **必须 {具体行为}** —— {为什么这样做,不这样做的具体后果}。
528
+ - **必须 {具体行为}** —— {后果}。
529
+ - **必须 {具体行为}** —— {后果}。
530
+ ```
531
+
532
+ ###### 3️⃣ ✅ 正例(摘自 live/coguest-apply)
533
+ ```markdown
534
+ ### ✅ ALWAYS
535
+
536
+ - **必须等主播同意后再开摄像头/麦克风** —— 提前开会让用户以为已上麦,
537
+ 实际未上麦时画面没人看,造成隐私焦虑。
538
+ - **必须为申请操作设置超时** —— 主播长时间不响应时,观众端 UI 卡住,
539
+ 用户以为 App 崩溃。建议默认 30 秒。
540
+ - **必须在断开连麦时关闭设备** —— 否则摄像头指示灯一直亮,被用户截图发微博
541
+ 投诉"偷拍"。
542
+ ```
543
+
544
+ 为什么这是正例:
545
+ - ✅ 用强动词("必须等""必须设置""必须关闭"),不用"建议""最好"
546
+ - ✅ 每条都说明了**具体后果**(隐私焦虑/UI 卡住/被投诉偷拍)
547
+ - ✅ 「2024 年发生过」= 失败记忆锚定,让规则有真实重量
548
+ - ✅ 描述行为不指定 API,跨平台都适用
549
+
550
+ ###### 4️⃣ ❌ 反例
551
+ ```markdown
552
+ ### ✅ ALWAYS
553
+
554
+ - 建议处理好申请超时的情况。
555
+ - 注意设备的开关时机。
556
+ - 一般来说要给用户友好的提示。
557
+ ```
558
+
559
+ 为什么这是反例:
560
+ - ❌ "建议/注意/一般来说" = 软词 → AI 视作可选 → 跳过
561
+ - ❌ "处理好""友好" = 模糊形容词 → AI 不知道具体做什么
562
+ - ❌ 没说后果 → 新人不会重视
563
+ - → review 时直接打回
564
+
565
+ ###### 5️⃣ 必填项语义三件套
566
+ - **违反后果**:ALWAYS 不到 3 条 / 含软词("建议""最好""一般来说""尽量")/ 缺少后果说明 → slice 不可合并
567
+ - **验证手段**:
568
+ ```bash
569
+ grep -E "建议|最好|一般来说|尽量|可能" {file} # 必须命中 0 次
570
+ # ALWAYS 条目数 ≥ 3
571
+ ```
572
+ - **绕过条件**:能力极简单(<10 行代码)且无历史踩坑 → 可降至 2 条,需在 PR 中证明
573
+
574
+ ---
575
+
576
+ ##### 最佳实践 - NEVER [必填,至少 3 条]
577
+
578
+ ###### 1️⃣ 你必须写什么
579
+ 列出用户在该能力上**真实踩过坑**的反向规则。
580
+ NEVER 的本质 = 反合理化——预先驳斥"为什么我可以这样做"的借口。
581
+
582
+ ###### 2️⃣ 写作模板
583
+ ```markdown
584
+ ### ❌ NEVER
585
+
586
+ - **绝不要 {具体行为}** —— {如果做了会发生什么具体后果}。
587
+ 即使 {常见的合理化借口},也不可以——{反驳}。
588
+
589
+ - **绝不要 {具体行为}** —— {后果}。
590
+ 即使 {借口},也不可以——{反驳}。
591
+ ```
592
+
593
+ ###### 3️⃣ ✅ 正例(摘自 chat/multi-instance)
594
+ ```markdown
595
+ ### ❌ NEVER
596
+
597
+ - **绝不要在收到互踢回调时立刻自动重新登录** —— 会形成两端死循环互踢,
598
+ 最终两端都登不上去。即使"用户体验考虑想自动恢复",也不可以——
599
+ 正确做法是弹窗让用户选择(本端继续 / 切回原端)。
600
+
601
+ - **绝不要把 SDKAppID 和 SecretKey 写在客户端代码里** —— SecretKey 泄露后
602
+ 攻击者可签发任意身份 UserSig。即使"只是 demo 临时用",也不可以——
603
+ demo 也会被截图、被复制到生产代码。
604
+
605
+ - **绝不要在登录未完成时调用任何业务 API** —— SDK 内部状态未就绪,
606
+ 调用结果不可预期(可能返回成功但实际未发送)。即使"看起来登录已经
607
+ 发起了",也不可以——必须等 onLoginSuccess 回调。
608
+ ```
609
+
610
+ 为什么这是正例:
611
+ - ✅ 用了"绝不要"的**强化语义**,而非"建议不要"
612
+ - ✅ 每条都说明了**具体后果**(死循环 / SecretKey 泄露 / 静默失败)
613
+ - ✅ 预先驳斥了**常见借口**(用户体验 / 只是 demo / 看起来发起了)——这是反合理化
614
+ - ✅ 给出了**替代行为**(弹窗 / 服务端签发 / 等回调)
615
+
616
+ ###### 4️⃣ ❌ 反例
617
+ ```markdown
618
+ ### ❌ NEVER
619
+
620
+ - 不建议在互踢回调里自动重登,可能会有问题。
621
+ - 注意 SecretKey 的安全性,最好不要放客户端。
622
+ - 一般来说要处理好登录失败的情况。
623
+ ```
624
+
625
+ 为什么这是反例:
626
+ - ❌ "不建议 / 最好 / 一般来说" = 软词,AI 读到判断"可选"而跳过
627
+ - ❌ "可能会有问题" = 没说清后果,新人不会重视
628
+ - ❌ "处理好" = 模糊动词,AI 不知道具体要做什么
629
+ - ❌ 没有反合理化——AI 想跳过时找不到反驳
630
+ - → review 时直接打回
631
+
632
+ ###### 5️⃣ 必填项语义三件套
633
+ - **违反后果**:NEVER 不到 3 条 / 含软词 / 缺少后果说明 / 缺少反合理化 → slice 不可合并
634
+ - **验证手段**:
635
+ ```bash
636
+ grep -E "不建议|最好|一般来说|可能|建议不要" {file} # 命中 0 次
637
+ # NEVER 条目数 ≥ 3
638
+ # 每条必须含"即使...也不可以"或等价反驳句式
639
+ ```
640
+ - **绕过条件**:能力本身简单到没有踩坑历史(需在 PR 中证明:搜过 ticket、issue、客户群均无相关问题)
641
+
642
+ ---
643
+
644
+ ##### 排障指南 - 常见错误码 [必填]
645
+
646
+ ###### 1️⃣ 你必须写什么
647
+ 列出**跨平台统一**的错误码及其含义、原因、处理动作。仅某平台特有的错误码下沉到平台文件。
648
+
649
+ ###### 2️⃣ 写作模板
650
+ ```markdown
651
+ ### 常见错误码
652
+
653
+ | 错误码 | 含义 | 常见原因 | 处理动作 |
654
+ |--------|------|---------|---------|
655
+ | {code} | {一句话含义} | {原因 1} / {原因 2} | {具体动作} |
656
+ | {code} | ... | ... | ... |
657
+ ```
658
+
659
+ ###### 3️⃣ ✅ 正例(摘自 chat/multi-instance)
660
+ ```markdown
661
+ ### 常见错误码
662
+
663
+ | 错误码 | 含义 | 常见原因 | 处理动作 |
664
+ |--------|------|---------|---------|
665
+ | 6206 | 互踢:被同账号其他端踢下线 | 用户在新设备登录;策略=互踢模式 | 弹窗提示用户「您的账号已在其他设备登录」,不要自动重登 |
666
+ | 6208 | 多端登录数超限 | 当前套餐允许的端数已满 | 提示用户先在其他设备退出;或升级套餐 |
667
+ | 70001 | UserSig 校验失败 | UserSig 过期 / 错误 / SDKAppID 不匹配 | 重新从服务端获取 UserSig,不要重试当前 sig |
668
+ ```
669
+
670
+ 为什么这是正例:
671
+ - ✅ 4 列结构清晰,每列职责单一
672
+ - ✅ "常见原因"列了 ≥1 个具体原因,不是泛化的"网络问题"
673
+ - ✅ "处理动作"是**具体动作**("弹窗提示""不要自动重登"),不是"处理一下"
674
+ - ✅ 错误码用真实数字,不是 `XXX001`
675
+
676
+ ###### 4️⃣ ❌ 反例
677
+ ```markdown
678
+ ### 常见错误码
679
+
680
+ 错误码很多,常见的有 6206、6208 等。具体含义参见官方文档。
681
+ 出错时一般可以重试或联系技术支持。
682
+ ```
683
+
684
+ 为什么这是反例:
685
+ - ❌ 不是表格,无法被 AI 结构化提取
686
+ - ❌ "参见官方文档" = 偷懒,AI 拿不到信息
687
+ - ❌ "可以重试" = 错!互踢错误重试会死循环
688
+ - → review 时直接打回
689
+
690
+ ###### 5️⃣ 必填项语义三件套
691
+ - **违反后果**:错误码缺失或处理动作错误 → AI 生成的错误处理代码会让用户陷入死循环或静默失败
692
+ - **验证手段**:必须是表格格式;每行 4 列齐全;"处理动作"列不含"重试""联系技术支持"等空洞词
693
+ - **绕过条件**:该能力没有专属错误码(全部走通用错误码),需在 PR 说明并引用 `{product}/error-codes`
694
+
695
+ ---
696
+
697
+ ##### 排障指南 - 排障流程 [必填]
698
+
699
+ ###### 1️⃣ 你必须写什么
700
+ 画一棵**通用排障树**:从症状出发,按"先查什么、再查什么"的顺序展开。平台特有分支标注 → 见平台文件。
701
+
702
+ ###### 2️⃣ 写作模板
703
+ ```markdown
704
+ ### 排障流程
705
+
706
+ 症状:{用户报的现象}
707
+ ├─ 检查 {基础项 1}?
708
+ │ ├─ 是 → 继续
709
+ │ └─ 否 → {处理动作}
710
+ ├─ 检查 {基础项 2}?
711
+ │ ├─ 是 → 继续
712
+ │ └─ 否 → {处理动作}
713
+ └─ 都正常但仍有问题 → 见平台文件 / 升级支持
714
+ ```
715
+
716
+ ###### 3️⃣ ✅ 正例(摘自 chat/msg-send)
717
+ ```markdown
718
+ ### 排障流程
719
+
720
+ 症状:消息发送返回失败 / 长时间无回调
721
+
722
+ ├─ 登录是否完成?(loginStatus == LOGGED_IN)
723
+ │ ├─ 是 → 继续
724
+ │ └─ 否 → 等待 onLoginSuccess 后重发(→ chat/login-auth)
725
+ ├─ 错误码是否为 70001(UserSig 失败)?
726
+ │ ├─ 是 → 重新从服务端获取 UserSig,不要本地重试
727
+ │ └─ 否 → 继续
728
+ ├─ 错误码是否为 80001(消息内容违规)?
729
+ │ ├─ 是 → 检查文本是否含敏感词,提示用户修改内容
730
+ │ └─ 否 → 继续
731
+ ├─ 接收方是否被发送方加入黑名单?
732
+ │ ├─ 否 → 继续
733
+ │ └─ 是 → 提示"对方拒绝接收消息"
734
+ └─ 都正常但仍失败 → 平台特有排障(→ chat/{platform}/msg-send)
735
+ ```
736
+
737
+ 为什么这是正例:
738
+ - ✅ 从症状出发,符合客户思维顺序
739
+ - ✅ 每个检查项都有"是/否"分支,不留模糊
740
+ - ✅ 引用了其他 slice(`chat/login-auth`、`chat/{platform}/msg-send`),不重复
741
+ - ✅ 兜底分支明确(平台文件)
742
+
743
+ ###### 4️⃣ ❌ 反例
744
+ ```markdown
745
+ ### 排障流程
746
+
747
+ 如果消息发不出去,先检查网络,再检查登录状态,然后看错误码。
748
+ 还不行就联系技术支持。
749
+ ```
750
+
751
+ 为什么这是反例:
752
+ - ❌ 不是树形结构,AI 无法按顺序提取检查项
753
+ - ❌ "先...再...然后" = 模糊顺序,没说"否"分支怎么办
754
+ - ❌ "联系技术支持" = 兜底没意义,AI 拿不到任何动作
755
+ - → review 时直接打回
756
+
757
+ ###### 5️⃣ 必填项语义三件套
758
+ - **违反后果**:排障流程不成树/不可执行 → AI 排障建议变成"再试一次/联系技术支持"等无效话术 → 用户报"AI 没用"
759
+ - **验证手段**:必须是树形(用 `├─└─` 或类似)、每个分支有明确"是/否"、兜底必须指向具体 slice 或行动
760
+ - **绕过条件**:无
761
+
762
+ ---
763
+
764
+ ##### 关联知识 [可选]
765
+
766
+ 引用相关 slice。如果没有关联,删除整个 section。
767
+ 有 ≥2 相关 slice 时**必填**(防止知识孤岛)。
768
+
769
+ ```markdown
770
+ ## 关联知识
771
+
772
+ - [chat/login-auth](./login-auth.md) — 登录认证(本 slice 的前置)
773
+ - [chat/error-codes](./error-codes.md) — 完整错误码总表
774
+ ```
775
+
776
+ ---
777
+
778
+ ##### 产品级概览各 section 的必填理由
779
+
780
+ - `功能说明` / `核心概念` — slice 的身份标识,缺失则无法理解 slice 是做什么的
781
+ - `最佳实践` — slice 区别于官方文档的核心价值。仅抄 API 说明,无需做 slice
782
+ - `排障指南` — slice 面向集成场景的交付标准。至少给出「常见错误码」和「排障流程」两个子项,否则客户报问题时无章可循
783
+ - `关联知识` — 孤立能力可省。有 2+ 相关 slice 时必须写,防止知识孤岛
784
+ ```
785
+
786
+ 各 section 详细要求见下方。
787
+
788
+ ---
789
+
790
+ ##### 功能说明 [必填]
791
+
792
+ ###### 1️⃣ 你必须写什么
793
+ 一段 100-200 字的散文,回答三个问题:
794
+ - 这个能力解决什么问题(用客户的语言,不用 SDK 术语)
795
+ - 典型业务场景举 1-2 个
796
+ - 最低 SDK 版本要求(若有)
797
+
798
+ ###### 2️⃣ 写作模板
799
+ ```markdown
800
+ ## 功能说明
801
+
802
+ {能力名}解决 {具体业务问题}。典型场景包括 {场景 1}、{场景 2}。
803
+
804
+ 要求 SDK 版本 ≥ {version}。{若有跨平台版本差异,说明}。
805
+ ```
806
+
807
+ ###### 3️⃣ ✅ 正例(摘自 chat/multi-instance)
808
+ ```markdown
809
+ ## 功能说明
810
+
811
+ 多端登录指同一用户在多个设备(手机、平板、Web)同时登录 IM 账号的能力。
812
+ 解决的问题是:用户在手机上聊天,切换到电脑也能继续,不需要被强制踢下线。
813
+ 典型场景:企业 IM(电脑+手机同时在线)、客服系统(坐席多端备份)。
814
+
815
+ 要求 IM SDK ≥ 7.0,需要在控制台开通"多端登录"套餐(基础版不支持)。
816
+ ```
817
+
818
+ 为什么这是正例:
819
+ - ✅ 第一句用客户语言("同时登录")而非 SDK 术语("multi-instance")
820
+ - ✅ 写出了"解决什么问题",新人 30 秒能 get
821
+ - ✅ 给了 2 个具体场景,不是空洞的"很多场景"
822
+ - ✅ 标注了版本和套餐要求(常见踩坑点)
823
+
824
+ ###### 4️⃣ ❌ 反例
825
+ ```markdown
826
+ ## 功能说明
827
+
828
+ 本 slice 介绍 multi-instance 功能。该功能允许用户在多端登录,
829
+ 具体使用方式参见后续章节。
830
+ ```
831
+
832
+ 为什么这是反例:
833
+ - ❌ "本 slice 介绍" = 元描述,AI 拿不到任何业务信息
834
+ - ❌ "具体使用方式参见后续章节" = 偷懒,等于没写
835
+ - ❌ 没说解决什么问题、没场景、没版本要求
836
+ - → review 时直接打回
837
+
838
+ ###### 5️⃣ 必填项语义三件套
839
+ - **违反后果**:功能说明缺失或空洞 → AI 路由准确率下降 30%+(无法判断是否匹配用户意图)→ 客户问对了问题但被引到错误 slice
840
+ - **验证手段**:人工 review,逐条对照"三个问题"是否答全;字数 100-200 之间
841
+ - **绕过条件**:无
842
+
843
+ ---
844
+
845
+ ##### 核心概念 [必填]
846
+
847
+ ###### 1️⃣ 你必须写什么
848
+ 用**操作名 + 语义描述**列出该能力涉及的核心概念。不写平台特有 API 签名。
849
+ 若有状态机/角色关系,画出来。
850
+
851
+ ###### 2️⃣ 写作模板
852
+ ```markdown
853
+ ## 核心概念
854
+
855
+ ### 涉及角色
856
+ - **{角色 1}**:{这个角色做什么}
857
+ - **{角色 2}**:{这个角色做什么}
858
+
859
+ ### 关键操作
860
+ | 操作名 | 语义 | 触发方 |
861
+ |--------|------|--------|
862
+ | {操作 1} | {做了什么} | {谁触发} |
863
+ | {操作 2} | {做了什么} | {谁触发} |
864
+
865
+ ### 状态机(如有)
866
+ {状态 A} → [{触发事件}] → {状态 B} → [{事件}] → {状态 C}
867
+ ```
868
+
869
+ ###### 3️⃣ ✅ 正例(摘自 live/coguest-apply)
870
+ ```markdown
871
+ ## 核心概念
872
+
873
+ ### 涉及角色
874
+ - **观众(Audience)**:发起连麦申请的一方,等待主播同意后上麦
875
+ - **主播(Host)**:接收申请并决定是否同意的一方,有最终决策权
876
+
877
+ ### 关键操作
878
+ | 操作名 | 语义 | 触发方 |
879
+ |--------|------|--------|
880
+ | 申请连麦 | 观众请求加入主播的麦位,带超时(默认 30s) | 观众 |
881
+ | 同意申请 | 主播接受请求,观众变为连麦者 | 主播 |
882
+ | 拒绝申请 | 主播拒绝请求,观众回到观众态 | 主播 |
883
+ | 取消申请 | 观众主动撤回未处理的申请 | 观众 |
884
+
885
+ ### 状态机
886
+ 观众态 → [申请连麦] → 申请中 → [主播同意] → 连麦中
887
+ → [主播拒绝/超时] → 观众态
888
+ → [观众取消] → 观众态
889
+ ```
890
+
891
+ 为什么这是正例:
892
+ - ✅ 角色定义在最前,后续操作都基于角色
893
+ - ✅ 每个操作有"触发方"列,明确谁能做什么
894
+ - ✅ 状态机用纯文字+箭头,不依赖任何平台框架
895
+ - ✅ 整段没出现任何 Swift/Kotlin/JS 语法
896
+
897
+ ###### 4️⃣ ❌ 反例
898
+ ```markdown
899
+ ## 核心概念
900
+
901
+ 观众调用 `CoGuestStore.shared.applyForSeat(timeout: 30)` 发起申请,
902
+ 主播订阅 `applicationReceived` 事件接收。申请超时会触发 `.failure` 回调。
903
+ ```
904
+
905
+ 为什么这是反例:
906
+ - ❌ `CoGuestStore.shared.xxx` = iOS Swift 语法 → 平台特有
907
+ - ❌ `.failure` = Swift Result 类型 → 平台特有
908
+ - ❌ 没区分角色、没状态机
909
+ - → 应整段下沉到 `live/ios/coguest-apply.md`,产品级概览改写为操作语义
910
+
911
+ ###### 5️⃣ 必填项语义三件套
912
+ - **违反后果**:出现平台特有 API → 跨平台 AI 生成时混淆(Android 开发者拿到 iOS 代码)→ 编译报错投诉
913
+ - **验证手段**:人工 review,过一遍每个 backtick 内的标识符,任一是平台特有 → 打回
914
+ - **绕过条件**:无
915
+
916
+ ---
917
+
918
+ ##### 最佳实践 - ALWAYS [必填,至少 3 条]
919
+
920
+ ###### 1️⃣ 你必须写什么
921
+ 列出**行为级**的"必须做的事"。描述"该做什么",不指定"用哪个 API 做"。
922
+
923
+ ###### 2️⃣ 写作模板
924
+ ```markdown
925
+ ### ✅ ALWAYS
926
+
927
+ - **必须 {具体行为}** —— {为什么这样做,不这样做的具体后果}。
928
+ - **必须 {具体行为}** —— {后果}。
929
+ - **必须 {具体行为}** —— {后果}。
930
+ ```
931
+
932
+ ###### 3️⃣ ✅ 正例(摘自 live/coguest-apply)
933
+ ```markdown
934
+ ### ✅ ALWAYS
935
+
936
+ - **必须等主播同意后再开摄像头/麦克风** —— 提前开会让用户以为已上麦,
937
+ 实际未上麦时画面没人看,造成隐私焦虑。
938
+ - **必须为申请操作设置超时** —— 主播长时间不响应时,观众端 UI 卡住,
939
+ 用户以为 App 崩溃。建议默认 30 秒。
940
+ - **必须在断开连麦时关闭设备** —— 否则摄像头指示灯一直亮,被用户截图发微博
941
+ 投诉"偷拍"。
942
+ ```
943
+
944
+ 为什么这是正例:
945
+ - ✅ 用强动词("必须等""必须设置""必须关闭"),不用"建议""最好"
946
+ - ✅ 每条都说明了**具体后果**(隐私焦虑/UI 卡住/被投诉偷拍)
947
+ - ✅ 「2024 年发生过」= 失败记忆锚定,让规则有真实重量
948
+ - ✅ 描述行为不指定 API,跨平台都适用
949
+
950
+ ###### 4️⃣ ❌ 反例
951
+ ```markdown
952
+ ### ✅ ALWAYS
953
+
954
+ - 建议处理好申请超时的情况。
955
+ - 注意设备的开关时机。
956
+ - 一般来说要给用户友好的提示。
957
+ ```
958
+
959
+ 为什么这是反例:
960
+ - ❌ "建议/注意/一般来说" = 软词 → AI 视作可选 → 跳过
961
+ - ❌ "处理好""友好" = 模糊形容词 → AI 不知道具体做什么
962
+ - ❌ 没说后果 → 新人不会重视
963
+ - → review 时直接打回
964
+
965
+ ###### 5️⃣ 必填项语义三件套
966
+ - **违反后果**:ALWAYS 不到 3 条 / 含软词("建议""最好""一般来说""尽量")/ 缺少后果说明 → slice 不可合并
967
+ - **验证手段**:
968
+ ```bash
969
+ grep -E "建议|最好|一般来说|尽量|可能" {file} # 必须命中 0 次
970
+ # ALWAYS 条目数 ≥ 3
971
+ ```
972
+ - **绕过条件**:能力极简单(<10 行代码)且无历史踩坑 → 可降至 2 条,需在 PR 中证明
973
+
974
+ ---
975
+
976
+ ##### 最佳实践 - NEVER [必填,至少 3 条]
977
+
978
+ ###### 1️⃣ 你必须写什么
979
+ 列出用户在该能力上**真实踩过坑**的反向规则。
980
+ NEVER 的本质 = 反合理化——预先驳斥"为什么我可以这样做"的借口。
981
+
982
+ ###### 2️⃣ 写作模板
983
+ ```markdown
984
+ ### ❌ NEVER
985
+
986
+ - **绝不要 {具体行为}** —— {如果做了会发生什么具体后果}。
987
+ 即使 {常见的合理化借口},也不可以——{反驳}。
988
+
989
+ - **绝不要 {具体行为}** —— {后果}。
990
+ 即使 {借口},也不可以——{反驳}。
991
+ ```
992
+
993
+ ###### 3️⃣ ✅ 正例(摘自 chat/multi-instance)
994
+ ```markdown
995
+ ### ❌ NEVER
996
+
997
+ - **绝不要在收到互踢回调时立刻自动重新登录** —— 会形成两端死循环互踢,
998
+ 最终两端都登不上去。即使"用户体验考虑想自动恢复",也不可以——
999
+ 正确做法是弹窗让用户选择(本端继续 / 切回原端)。
1000
+
1001
+ - **绝不要把 SDKAppID 和 SecretKey 写在客户端代码里** —— SecretKey 泄露后
1002
+ 攻击者可签发任意身份 UserSig。即使"只是 demo 临时用",也不可以——
1003
+ demo 也会被截图、被复制到生产代码。
1004
+
1005
+ - **绝不要在登录未完成时调用任何业务 API** —— SDK 内部状态未就绪,
1006
+ 调用结果不可预期(可能返回成功但实际未发送)。即使"看起来登录已经
1007
+ 发起了",也不可以——必须等 onLoginSuccess 回调。
1008
+ ```
1009
+
1010
+ 为什么这是正例:
1011
+ - ✅ 用了"绝不要"的**强化语义**,而非"建议不要"
1012
+ - ✅ 每条都说明了**具体后果**(死循环 / SecretKey 泄露 / 静默失败)
1013
+ - ✅ 预先驳斥了**常见借口**(用户体验 / 只是 demo / 看起来发起了)——这是反合理化
1014
+ - ✅ 给出了**替代行为**(弹窗 / 服务端签发 / 等回调)
1015
+
1016
+ ###### 4️⃣ ❌ 反例
1017
+ ```markdown
1018
+ ### ❌ NEVER
1019
+
1020
+ - 不建议在互踢回调里自动重登,可能会有问题。
1021
+ - 注意 SecretKey 的安全性,最好不要放客户端。
1022
+ - 一般来说要处理好登录失败的情况。
1023
+ ```
1024
+
1025
+ 为什么这是反例:
1026
+ - ❌ "不建议 / 最好 / 一般来说" = 软词,AI 读到判断"可选"而跳过
1027
+ - ❌ "可能会有问题" = 没说清后果,新人不会重视
1028
+ - ❌ "处理好" = 模糊动词,AI 不知道具体要做什么
1029
+ - ❌ 没有反合理化——AI 想跳过时找不到反驳
1030
+ - → review 时直接打回
1031
+
1032
+ ###### 5️⃣ 必填项语义三件套
1033
+ - **违反后果**:NEVER 不到 3 条 / 含软词 / 缺少后果说明 / 缺少反合理化 → slice 不可合并
1034
+ - **验证手段**:
1035
+ ```bash
1036
+ grep -E "不建议|最好|一般来说|可能|建议不要" {file} # 命中 0 次
1037
+ # NEVER 条目数 ≥ 3
1038
+ # 每条必须含"即使...也不可以"或等价反驳句式
1039
+ ```
1040
+ - **绕过条件**:能力本身简单到没有踩坑历史(需在 PR 中证明:搜过 ticket、issue、客户群均无相关问题)
1041
+
1042
+ ---
1043
+
1044
+ ##### 排障指南 - 常见错误码 [必填]
1045
+
1046
+ ###### 1️⃣ 你必须写什么
1047
+ 列出**跨平台统一**的错误码及其含义、原因、处理动作。仅某平台特有的错误码下沉到平台文件。
1048
+
1049
+ ###### 2️⃣ 写作模板
1050
+ ```markdown
1051
+ ### 常见错误码
1052
+
1053
+ | 错误码 | 含义 | 常见原因 | 处理动作 |
1054
+ |--------|------|---------|---------|
1055
+ | {code} | {一句话含义} | {原因 1} / {原因 2} | {具体动作} |
1056
+ | {code} | ... | ... | ... |
1057
+ ```
1058
+
1059
+ ###### 3️⃣ ✅ 正例(摘自 chat/multi-instance)
1060
+ ```markdown
1061
+ ### 常见错误码
1062
+
1063
+ | 错误码 | 含义 | 常见原因 | 处理动作 |
1064
+ |--------|------|---------|---------|
1065
+ | 6206 | 互踢:被同账号其他端踢下线 | 用户在新设备登录;策略=互踢模式 | 弹窗提示用户「您的账号已在其他设备登录」,不要自动重登 |
1066
+ | 6208 | 多端登录数超限 | 当前套餐允许的端数已满 | 提示用户先在其他设备退出;或升级套餐 |
1067
+ | 70001 | UserSig 校验失败 | UserSig 过期 / 错误 / SDKAppID 不匹配 | 重新从服务端获取 UserSig,不要重试当前 sig |
1068
+ ```
1069
+
1070
+ 为什么这是正例:
1071
+ - ✅ 4 列结构清晰,每列职责单一
1072
+ - ✅ "常见原因"列了 ≥1 个具体原因,不是泛化的"网络问题"
1073
+ - ✅ "处理动作"是**具体动作**("弹窗提示""不要自动重登"),不是"处理一下"
1074
+ - ✅ 错误码用真实数字,不是 `XXX001`
1075
+
1076
+ ###### 4️⃣ ❌ 反例
1077
+ ```markdown
1078
+ ### 常见错误码
1079
+
1080
+ 错误码很多,常见的有 6206、6208 等。具体含义参见官方文档。
1081
+ 出错时一般可以重试或联系技术支持。
1082
+ ```
1083
+
1084
+ 为什么这是反例:
1085
+ - ❌ 不是表格,无法被 AI 结构化提取
1086
+ - ❌ "参见官方文档" = 偷懒,AI 拿不到信息
1087
+ - ❌ "可以重试" = 错!互踢错误重试会死循环
1088
+ - → review 时直接打回
1089
+
1090
+ ###### 5️⃣ 必填项语义三件套
1091
+ - **违反后果**:错误码缺失或处理动作错误 → AI 生成的错误处理代码会让用户陷入死循环或静默失败
1092
+ - **验证手段**:必须是表格格式;每行 4 列齐全;"处理动作"列不含"重试""联系技术支持"等空洞词
1093
+ - **绕过条件**:该能力没有专属错误码(全部走通用错误码),需在 PR 说明并引用 `{product}/error-codes`
1094
+
1095
+ ---
1096
+
1097
+ ##### 排障指南 - 排障流程 [必填]
1098
+
1099
+ ###### 1️⃣ 你必须写什么
1100
+ 画一棵**通用排障树**:从症状出发,按"先查什么、再查什么"的顺序展开。平台特有分支标注 → 见平台文件。
1101
+
1102
+ ###### 2️⃣ 写作模板
1103
+ ```markdown
1104
+ ### 排障流程
1105
+
1106
+ 症状:{用户报的现象}
1107
+ ├─ 检查 {基础项 1}?
1108
+ │ ├─ 是 → 继续
1109
+ │ └─ 否 → {处理动作}
1110
+ ├─ 检查 {基础项 2}?
1111
+ │ ├─ 是 → 继续
1112
+ │ └─ 否 → {处理动作}
1113
+ └─ 都正常但仍有问题 → 见平台文件 / 升级支持
1114
+ ```
1115
+
1116
+ ###### 3️⃣ ✅ 正例(摘自 chat/msg-send)
1117
+ ```markdown
1118
+ ### 排障流程
1119
+
1120
+ 症状:消息发送返回失败 / 长时间无回调
1121
+
1122
+ ├─ 登录是否完成?(loginStatus == LOGGED_IN)
1123
+ │ ├─ 是 → 继续
1124
+ │ └─ 否 → 等待 onLoginSuccess 后重发(→ chat/login-auth)
1125
+ ├─ 错误码是否为 70001(UserSig 失败)?
1126
+ │ ├─ 是 → 重新从服务端获取 UserSig,不要本地重试
1127
+ │ └─ 否 → 继续
1128
+ ├─ 错误码是否为 80001(消息内容违规)?
1129
+ │ ├─ 是 → 检查文本是否含敏感词,提示用户修改内容
1130
+ │ └─ 否 → 继续
1131
+ ├─ 接收方是否被发送方加入黑名单?
1132
+ │ ├─ 否 → 继续
1133
+ │ └─ 是 → 提示"对方拒绝接收消息"
1134
+ └─ 都正常但仍失败 → 平台特有排障(→ chat/{platform}/msg-send)
1135
+ ```
1136
+
1137
+ 为什么这是正例:
1138
+ - ✅ 从症状出发,符合客户思维顺序
1139
+ - ✅ 每个检查项都有"是/否"分支,不留模糊
1140
+ - ✅ 引用了其他 slice(`chat/login-auth`、`chat/{platform}/msg-send`),不重复
1141
+ - ✅ 兜底分支明确(平台文件)
1142
+
1143
+ ###### 4️⃣ ❌ 反例
1144
+ ```markdown
1145
+ ### 排障流程
1146
+
1147
+ 如果消息发不出去,先检查网络,再检查登录状态,然后看错误码。
1148
+ 还不行就联系技术支持。
1149
+ ```
1150
+
1151
+ 为什么这是反例:
1152
+ - ❌ 不是树形结构,AI 无法按顺序提取检查项
1153
+ - ❌ "先...再...然后" = 模糊顺序,没说"否"分支怎么办
1154
+ - ❌ "联系技术支持" = 兜底没意义,AI 拿不到任何动作
1155
+ - → review 时直接打回
1156
+
1157
+ ###### 5️⃣ 必填项语义三件套
1158
+ - **违反后果**:排障流程不成树/不可执行 → AI 排障建议变成"再试一次/联系技术支持"等无效话术 → 用户报"AI 没用"
1159
+ - **验证手段**:必须是树形(用 `├─└─` 或类似)、每个分支有明确"是/否"、兜底必须指向具体 slice 或行动
1160
+ - **绕过条件**:无
1161
+
1162
+ ---
1163
+
1164
+ ##### 关联知识 [可选]
1165
+
1166
+ 引用相关 slice。如果没有关联,删除整个 section。
1167
+ 有 ≥2 相关 slice 时**必填**(防止知识孤岛)。
1168
+
1169
+ ```markdown
1170
+ ## 关联知识
1171
+
1172
+ - [chat/login-auth](./login-auth.md) — 登录认证(本 slice 的前置)
1173
+ - [chat/error-codes](./error-codes.md) — 完整错误码总表
1174
+ ```
1175
+
1176
+ ---
1177
+
1178
+ ##### 产品级概览各 section 的必填理由
1179
+
1180
+ - `功能说明` / `核心概念` — slice 的身份标识,缺失则无法理解 slice 是做什么的
1181
+ - `最佳实践` — slice 区别于官方文档的核心价值。仅抄 API 说明,无需做 slice
1182
+ - `排障指南` — slice 面向集成场景的交付标准。至少给出「常见错误码」和「排障流程」两个子项,否则客户报问题时无章可循
1183
+ - `关联知识` — 孤立能力可省。有 2+ 相关 slice 时必须写,防止知识孤岛
1184
+
1185
+ > 提交前对照第五节「产品级概览 DoD」逐条打勾,合格后再提交。
1186
+
1187
+ ---
1188
+ > 提交前对照第五节「产品级概览 DoD」逐条打勾,合格后再提交。
1189
+
1190
+ ---
1191
+
1192
+ #### 平台实现文件(`{product}/{platform}/{ability}.md`)
1193
+ #### 平台实现文件(`{product}/{platform}/{ability}.md`)
1194
+
1195
+ ##### Frontmatter 字段
1196
+
1197
+ ```yaml
1198
+ ---
1199
+ id: {product}/{ability} # [必填] 与产品级 slice 的 id 一致
1200
+ platform: {platform} # [必填] ios / android / web / flutter / electron
1201
+ api_docs: # [必填] 该平台 API 参考文档链接(至少 1 条)
1202
+ api_docs: # [必填] 该平台 API 参考文档链接(至少 1 条)
1203
+ - title: {API 类名/模块名}
1204
+ url: https://...
1205
+ ---
1206
+ ```
1207
+
1208
+ > 注:`name` / `tags` / `platforms` / `related` 在产品级概览中维护,平台文件不重复。
1209
+
1210
+ ---
1211
+
1212
+ ##### `api_docs` 字段 [必填,至少 1 条]
1213
+
1214
+ ###### 1️⃣ 你必须写什么
1215
+ 该平台 API 参考文档的**类/模块级**链接,AI 用它校验生成的 API 签名是否真实存在。
1216
+
1217
+ ###### 2️⃣ 写作模板
1218
+ ```yaml
1219
+ api_docs:
1220
+ - title: {本 slice 涉及的具体类名,如 CoGuestStore}
1221
+ url: https://{平台 SDK 文档站}/.../{类名小写}/
1222
+ ```
1223
+
1224
+ 判定链接是否合格:
1225
+ - 打开链接,**第一屏**就能看到本 slice 涉及的**具体类的方法签名**(参数名、参数类型、返回值)→ ✅ 合格
1226
+ - 第一屏只有概念介绍、教程文字 → ❌ 不合格
1227
+
1228
+ ###### 3️⃣ ✅ 正例(摘自 live/ios/coguest-apply)
1229
+ ```yaml
1230
+ api_docs:
1231
+ - title: CoGuestStore
1232
+ url: https://tencent-rtc.github.io/TUIKit_iOS/documentation/atomicxcore/cogueststore/
1233
+ - title: DeviceStore
1234
+ url: https://tencent-rtc.github.io/TUIKit_iOS/documentation/atomicxcore/devicestore/
1235
+ ```
1236
+
1237
+ 为什么这是正例:
1238
+ - ✅ 链接路径含 `/documentation/` → 是 API 参考站
1239
+ - ✅ 路径末尾是具体类名 `cogueststore` → 精确到类
1240
+ - ✅ slice 涉及两个 Store → 分别列出,不省略
1241
+
1242
+ ###### 4️⃣ ❌ 反例
1243
+ ```yaml
1244
+ # 反例 1:SDK 首页
1245
+ api_docs:
1246
+ - title: TRTC iOS SDK
1247
+ url: https://trtc.io/sdk
1248
+ # → AI 拿首页内容当类签名,会生成不存在的 API
1249
+
1250
+ # 反例 2:教程页
1251
+ api_docs:
1252
+ - title: 连麦集成指南
1253
+ url: https://trtc.io/zh/document/74598
1254
+ # → 教程页的 API 名常被简化(省命名空间),AI 会生成错误的引用语句
1255
+
1256
+ # 反例 3:链接为空或 TODO
1257
+ api_docs:
1258
+ - title: TODO
1259
+ url: TODO
1260
+ # → 占位的链接永远不会被替换,半年后这条 slice 就是废的
1261
+ ```
1262
+
1263
+ ###### 5️⃣ 必填项语义三件套
1264
+ - **违反后果**:链接非类级 → AI 生成不存在的 API 名 → 客户编译报错投诉(2025-Q1 真实事故,接入 2 天后才发现)
1265
+ - **验证手段**:
1266
+ ```bash
1267
+ python scripts/validate_api_docs.py {file}
1268
+ # 通过标准:每条 url 返回 200;url 含 `/documentation/` 或 `/api/`;
1269
+ # 打开链接的页面 H1 必须包含 frontmatter 里的 title
1270
+ ```
1271
+ - **绕过条件**:该平台官方确实无 API 参考站(如某些早期 Electron 模块)→ 必须填头文件 GitHub 永久链接(含 commit hash),且在 PR 中说明
1272
+
1273
+ ---
1274
+ > 注:`name` / `tags` / `platforms` / `related` 在产品级概览中维护,平台文件不重复。
1275
+
1276
+ ---
1277
+
1278
+ ##### `api_docs` 字段 [必填,至少 1 条]
1279
+
1280
+ ###### 1️⃣ 你必须写什么
1281
+ 该平台 API 参考文档的**类/模块级**链接,AI 用它校验生成的 API 签名是否真实存在。
1282
+
1283
+ ###### 2️⃣ 写作模板
1284
+ ```yaml
1285
+ api_docs:
1286
+ - title: {本 slice 涉及的具体类名,如 CoGuestStore}
1287
+ url: https://{平台 SDK 文档站}/.../{类名小写}/
1288
+ ```
1289
+
1290
+ 判定链接是否合格:
1291
+ - 打开链接,**第一屏**就能看到本 slice 涉及的**具体类的方法签名**(参数名、参数类型、返回值)→ ✅ 合格
1292
+ - 第一屏只有概念介绍、教程文字 → ❌ 不合格
1293
+
1294
+ ###### 3️⃣ ✅ 正例(摘自 live/ios/coguest-apply)
1295
+ ```yaml
1296
+ api_docs:
1297
+ - title: CoGuestStore
1298
+ url: https://tencent-rtc.github.io/TUIKit_iOS/documentation/atomicxcore/cogueststore/
1299
+ - title: DeviceStore
1300
+ url: https://tencent-rtc.github.io/TUIKit_iOS/documentation/atomicxcore/devicestore/
1301
+ ```
1302
+
1303
+ 为什么这是正例:
1304
+ - ✅ 链接路径含 `/documentation/` → 是 API 参考站
1305
+ - ✅ 路径末尾是具体类名 `cogueststore` → 精确到类
1306
+ - ✅ slice 涉及两个 Store → 分别列出,不省略
1307
+
1308
+ ###### 4️⃣ ❌ 反例
1309
+ ```yaml
1310
+ # 反例 1:SDK 首页
1311
+ api_docs:
1312
+ - title: TRTC iOS SDK
1313
+ url: https://trtc.io/sdk
1314
+ # → AI 拿首页内容当类签名,会生成不存在的 API
1315
+
1316
+ # 反例 2:教程页
1317
+ api_docs:
1318
+ - title: 连麦集成指南
1319
+ url: https://trtc.io/zh/document/74598
1320
+ # → 教程页的 API 名常被简化(省命名空间),AI 会生成错误的引用语句
1321
+
1322
+ # 反例 3:链接为空或 TODO
1323
+ api_docs:
1324
+ - title: TODO
1325
+ url: TODO
1326
+ # → 占位的链接永远不会被替换,半年后这条 slice 就是废的
1327
+ ```
1328
+
1329
+ ###### 5️⃣ 必填项语义三件套
1330
+ - **违反后果**:链接非类级 → AI 生成不存在的 API 名 → 客户编译报错投诉(2025-Q1 真实事故,接入 2 天后才发现)
1331
+ - **验证手段**:
1332
+ ```bash
1333
+ python scripts/validate_api_docs.py {file}
1334
+ # 通过标准:每条 url 返回 200;url 含 `/documentation/` 或 `/api/`;
1335
+ # 打开链接的页面 H1 必须包含 frontmatter 里的 title
1336
+ ```
1337
+ - **绕过条件**:该平台官方确实无 API 参考站(如某些早期 Electron 模块)→ 必须填头文件 GitHub 永久链接(含 commit hash),且在 PR 中说明
1338
+
1339
+ ---
1340
+
1341
+ ##### 内容结构
1342
+
1343
+ 平台实现文件按以下结构编写,每个 section 标题都必须带必填/可选标签:
1344
+ 平台实现文件按以下结构编写,每个 section 标题都必须带必填/可选标签:
1345
+
1346
+ ```markdown
1347
+ # {名称} — {平台} 实现
1348
+
1349
+ ## 前置条件 [必填]
1350
+ ## 代码示例 [必填]
1351
+ ## 调用时序 [条件必填:多角色异步交互 或 回调嵌套 ≥3 层]
1352
+ ## 平台特有注意事项 [必填:至少 1 条]
1353
+ ## 调用时序 [条件必填:多角色异步交互 或 回调嵌套 ≥3 层]
1354
+ ## 平台特有注意事项 [必填:至少 1 条]
1355
+ ## 代码生成约束 [必填]
1356
+ ## 验证矩阵 [必填]
1357
+ ```
1358
+
1359
+ 各 section 详细要求见下方。
1360
+
1361
+ ---
1362
+
1363
+ ##### 前置条件 [必填]
1364
+
1365
+ ###### 1️⃣ 你必须写什么
1366
+ 列出本 slice 代码运行前必须满足的状态,**用引用形式**指向其他 slice,不要重复其他 slice 的安装/配置步骤。
1367
+
1368
+ ###### 2️⃣ 写作模板
1369
+ ```markdown
1370
+ ## 前置条件
1371
+
1372
+ - 已完成 SDK 初始化(→ {product}/base-setup)
1373
+ - 已完成登录(→ {product}/login-auth),`LoginStore.shared.isLogin == true`
1374
+ - 已加入房间(→ {product}/room-lifecycle),房间状态 = JOINED
1375
+ - {本 slice 特有的额外前置条件}
1376
+ ```
1377
+
1378
+ ###### 3️⃣ ✅ 正例
1379
+ ```markdown
1380
+ ## 前置条件
1381
+
1382
+ - 已完成 SDK 初始化与登录(→ live/login-auth)
1383
+ - 已加入房间且角色为观众(→ live/room-lifecycle),`RoomStore.shared.localUser.role == .audience`
1384
+ - 主播端已开播且开启了"接受连麦申请"开关
1385
+ ```
1386
+
1387
+ 为什么这是正例:
1388
+ - ✅ 用 `→ slice-id` 标注依赖,不重复说明怎么登录
1389
+ - ✅ 给出可机械验证的状态条件(`role == .audience`)
1390
+ - ✅ 包含跨角色前置(主播端配置)
1391
+
1392
+ ###### 4️⃣ ❌ 反例
1393
+ ```markdown
1394
+ ## 前置条件
11
1395
 
12
- **类比**:如果 TRTC SDK 是一台车,slice 就是驾驶手册里的一个章节——"怎么启动"、"怎么倒车"、"怎么用定速巡航",每一章独立可读,合在一起就是完整手册。
1396
+ 要先安装 SDK `pod 'TUIKit'`,然后调用 `LoginStore.login(userId:userSig:)` 登录,
1397
+ 然后调用 `RoomStore.joinRoom(roomId:)` 加入房间,...
1398
+ ```
1399
+
1400
+ 为什么这是反例:
1401
+ - ❌ 重复了 base-setup / login-auth 的内容
1402
+ - ❌ 这些内容会随版本变化,这里写一份等于埋雷
1403
+ - → 改为 `→ live/login-auth` 引用
1404
+
1405
+ ###### 5️⃣ 必填项语义三件套
1406
+ - **违反后果**:重复其他 slice 内容 → 信息漂移(版本升级后这里没同步)→ AI 生成过时代码
1407
+ - **验证手段**:全文搜 `pod install`/`npm install`/`implementation` 等安装关键字 → 应命中 0 次(都已下沉到 base-setup)
1408
+ - **绕过条件**:无
13
1409
 
14
1410
  ---
15
1411
 
16
- ## 二、Slice 拆分标准
1412
+ ##### 代码示例 [必填]
17
1413
 
18
- ### 核心原则
1414
+ ###### 1️⃣ 你必须写什么
1415
+ 能让 AI 直接学习并产出**可编译、可运行**的代码块。
1416
+ 代码示例 = 这份 slice 给 AI 的"训练数据",每个细节都会被复制放大。
19
1417
 
20
- > **一个 slice = 用户遇到一个具体问题时,我们能一次性讲清楚的内容。**
1418
+ ###### 2️⃣ 6 条最低标准
1419
+ ---
21
1420
 
22
- ### 判断方法:三个问题
1421
+ ##### 前置条件 [必填]
23
1422
 
24
- #### 问题 1:「能不能一次讲清楚?」
1423
+ ###### 1️⃣ 你必须写什么
1424
+ 列出本 slice 代码运行前必须满足的状态,**用引用形式**指向其他 slice,不要重复其他 slice 的安装/配置步骤。
25
1425
 
26
- 如果客户来问这个问题,技术支持能不能在**一次沟通**中完整解决?
1426
+ ###### 2️⃣ 写作模板
1427
+ ```markdown
1428
+ ## 前置条件
27
1429
 
28
- | 判断 | 举例 | 说明 |
29
- |------|------|------|
30
- | 合适 | "多端登录老是互踢怎么办?" | 讲清楚策略配置 + 回调处理 + 常见错误码就行 |
31
- | 合适 | "消息发不出去" | 讲清楚发送流程 + 权限检查 + 错误码就行 |
32
- | ❌ 太大了 | "消息功能怎么做?" | 发送、接收、历史记录、撤回、已读... 一次说不完 |
33
- | ❌ 太小了 | "怎么设置消息的优先级字段?" | 就一个参数,不值得单独做 |
1430
+ - 已完成 SDK 初始化(→ {product}/base-setup)
1431
+ - 已完成登录(→ {product}/login-auth),`LoginStore.shared.isLogin == true`
1432
+ - 已加入房间(→ {product}/room-lifecycle),房间状态 = JOINED
1433
+ - {本 slice 特有的额外前置条件}
1434
+ ```
34
1435
 
35
- **简单判断**:想象客户发来一条微信问这个问题,你用**一段话或一个截图**能不能回答?能 合适的粒度。需要连续发好几屏 → 太大。回复一句话就搞定 → 太小,可以合并到相关功能里。
1436
+ ###### 3️⃣ 正例
1437
+ ```markdown
1438
+ ## 前置条件
36
1439
 
37
- #### 问题 2:「出问题时,排查方向一样吗?」
1440
+ - 已完成 SDK 初始化与登录(→ live/login-auth)
1441
+ - 已加入房间且角色为观众(→ live/room-lifecycle),`RoomStore.shared.localUser.role == .audience`
1442
+ - 主播端已开播且开启了"接受连麦申请"开关
1443
+ ```
38
1444
 
39
- 如果两个功能出问题后,排查思路完全不同,就应该拆成两个 slice。
1445
+ 为什么这是正例:
1446
+ - ✅ 用 `→ slice-id` 标注依赖,不重复说明怎么登录
1447
+ - ✅ 给出可机械验证的状态条件(`role == .audience`)
1448
+ - ✅ 包含跨角色前置(主播端配置)
40
1449
 
41
- | 场景 | 排查方向 | 结论 |
42
- |------|---------|------|
43
- | "消息发不出去" vs "收不到消息" | 发送查网络/权限/格式,接收查监听/登录状态/群设置 | → **拆成两个** |
44
- | "发文本消息" vs "发图片消息" | 都是查消息格式和网络 | → **合成一个**(发送消息) |
45
- | "主播无法开播" vs "连麦布局不对" | 开播查权限/配置,布局查模板参数 | → **拆成两个** |
1450
+ ###### 4️⃣ 反例
1451
+ ```markdown
1452
+ ## 前置条件
46
1453
 
47
- **简单判断**:客户报这两个问题的时候,你会不会分给同一个人处理?如果是,多半可以合并;如果你本能想找不同的人来看,就该拆开。
1454
+ 要先安装 SDK 包 `pod 'TUIKit'`,然后调用 `LoginStore.login(userId:userSig:)` 登录,
1455
+ 然后调用 `RoomStore.joinRoom(roomId:)` 加入房间,...
1456
+ ```
48
1457
 
49
- #### 问题 3:「是独立的用户动作吗?」
1458
+ 为什么这是反例:
1459
+ - ❌ 重复了 base-setup / login-auth 的内容
1460
+ - ❌ 这些内容会随版本变化,这里写一份等于埋雷
1461
+ - → 改为 `→ live/login-auth` 引用
50
1462
 
51
- 一个 slice 应该对应一个用户能感知到的**独立操作步骤**。
1463
+ ###### 5️⃣ 必填项语义三件套
1464
+ - **违反后果**:重复其他 slice 内容 → 信息漂移(版本升级后这里没同步)→ AI 生成过时代码
1465
+ - **验证手段**:全文搜 `pod install`/`npm install`/`implementation` 等安装关键字 → 应命中 0 次(都已下沉到 base-setup)
1466
+ - **绕过条件**:无
52
1467
 
53
- | 场景 | 用户动作 | 结论 |
54
- |------|---------|------|
55
- | 配置准备页 → 点开播 → 进入直播间 | 这是一个连贯动作 | → **一个** slice(主播开播) |
56
- | 选择连麦布局模板 | 独立的配置决策 | → **单独一个** slice |
57
- | 隐藏某个按钮 + 改文案 + 换图标 | 都是"改 UI 外观"这一个动作 | → **合成一个** slice(UI 定制) |
1468
+ ---
58
1469
 
59
- #### 问题 4:「能被多个场景复用吗?」
1470
+ ##### 代码示例 [必填]
60
1471
 
61
- 一个 slice 应该能被 **2 个及以上** scenario(或其他 slice)引用。如果拆出来后只会被一个场景用到,通常说明它只是那个场景的一个步骤,而不是独立能力,应该合并回最相关的 slice。
1472
+ ###### 1️⃣ 你必须写什么
1473
+ 能让 AI 直接学习并产出**可编译、可运行**的代码块。
1474
+ 代码示例 = 这份 slice 给 AI 的"训练数据",每个细节都会被复制放大。
62
1475
 
63
- | 场景 | 复用性判断 | 结论 |
64
- |------|----------|------|
65
- | 「发送消息」 | 所有 Chat 相关 scenario 都会用 | → **独立 slice** |
66
- | 「进房」 | Live、Call、Room 所有场景共用 | → **独立 slice** |
67
- | 「主播开播前的网络探测提示」 | 只在「主播开播」这一个场景出现 | **合并到 `live/anchor-lifecycle`** |
68
- | 「连麦申请时的倒计时 UI 定制」 | 只有「观众申请连麦」会用 | **合并到 `live/coguest-apply`** |
1476
+ ###### 2️⃣ 6 条最低标准
1477
+
1478
+ | 维度 | 最低标准 |
1479
+ |------|---------|
1480
+ | **可编译** | 含完整 import、完整类/函数闭包,不允许 `...` 省略任何逻辑分支 |
1481
+ | **可运行** | 补充业务参数后可直接跑通;业务参数用 `{TODO: 填入 xxx}` 占位 |
1482
+ | **有日志锚点** | 关键路径(申请发送成功、主播同意、设备打开、失败分支)必须有 `print`/`console.log`/`Log.d`,带模块前缀如 `[CoGuest]` |
1483
+ | **有错误处理** | 每个 `.failure` / `catch` / `error` 分支必须有面向用户的处理(UI 可见的 `errorMessage` 或 `alert`),不允许只 `print` |
1484
+ | **多角色分开写** | 主播端 / 观众端这种异构角色,**必须**拆成独立示例代码块 |
1485
+ | **可组合性** | 对外暴露清晰输入/输出;依赖用注释标注 `// 前置:登录完成(→ live/login-auth)` |
1486
+
1487
+ ###### 3️⃣ 写作模板(以 iOS Swift 为例)
1488
+ ````markdown
1489
+ ### 场景 X:{场景名,如"观众发起连麦申请"}
1490
+
1491
+ ```swift
1492
+ // 前置:登录完成(→ chat/login-auth)
1493
+ // 前置:已加入房间(→ live/room-lifecycle)
1494
+
1495
+ import TencentImSDKPlugin
1496
+ import Combine
1497
+
1498
+ class CoGuestApplyViewModel: ObservableObject {
1499
+ @Published var errorMessage: String? // ← UI 必需,展示给用户
1500
+ private var cancellables = Set<AnyCancellable>()
1501
+
1502
+ func applyForSeat() {
1503
+ print("[CoGuest] 开始发起连麦申请") // ← 日志锚点(供验证矩阵层级 3)
1504
+
1505
+ CoGuestStore.shared.applyForSeat(timeout: 30)
1506
+ .sink { [weak self] completion in // ← [weak self] 必需
1507
+ if case .failure(let error) = completion {
1508
+ print("[CoGuest] 申请失败: \(error)")
1509
+ self?.errorMessage = "连麦申请失败,请重试" // ← 用户可见
1510
+ }
1511
+ } receiveValue: { [weak self] _ in
1512
+ print("[CoGuest] 申请已发送")
1513
+ self?.errorMessage = nil
1514
+ }
1515
+ .store(in: &cancellables)
1516
+ }
1517
+ }
1518
+ ```
1519
+ ````
1520
+
1521
+ ###### 4️⃣ ❌ 反例
1522
+ ```swift
1523
+ // 反例 1:用 ... 省略
1524
+ func applyForSeat() {
1525
+ CoGuestStore.shared.applyForSeat(...) { result in
1526
+ // 处理结果
1527
+ ...
1528
+ }
1529
+ }
1530
+ // → "..." 跳过了失败处理 → AI 学到这个模式后到处省略
1531
+
1532
+ // 反例 2:仅 print 错误
1533
+ .sink { completion in
1534
+ if case .failure(let error) = completion {
1535
+ print("error: \(error)") // ← 用户看不到!
1536
+ }
1537
+ }
1538
+ // → 客户线上故障时用户只看到无反应
1539
+
1540
+ // 反例 3:省略 import
1541
+ class XXX {
1542
+ var cancellables = Set<AnyCancellable>()
1543
+ // ↑ 没 import Combine,代码贴出来不能编译
1544
+ }
1545
+
1546
+ // 反例 4:业务参数瞎编
1547
+ applyForSeat(seatIndex: 1, timeout: 60, reason: "我想连麦")
1548
+ // → "我想连麦" 应该用 {TODO: 填入业务申请理由} 占位
1549
+
1550
+ // 反例 5:多角色塞一个类里
1551
+ class CoGuestManager {
1552
+ func audienceApply() { ... }
1553
+ func hostApprove() { ... }
1554
+ }
1555
+ // → 主播观众职责混合,AI 生成时随机抽方法
1556
+ ```
69
1557
 
70
- **唯一例外**:如果这个能力本身**极度独立、概念自洽、边界清晰**(即便当前只有一个引用方,未来很可能被复用),可以破例单拆。典型如「错误码速查」「日志诊断入口」这种跨能力的元能力。
1558
+ ###### 5️⃣ 必填项语义三件套
1559
+ - **违反后果**:含 `...` / 仅 print 错误 / 省略 import → AI 学坏 → 跨 slice 蔓延错误模式 → slice 不可合并,**已合并的批量回退**(2025-03 真实事故,2 周返工)
1560
+ - **验证手段**:
1561
+ ```bash
1562
+ # 1. 抽取代码块编译
1563
+ python scripts/extract_code.py {file} | xcodebuild build ...
1564
+ # 2. 静态扫描
1565
+ grep -E "\.\.\.|//\s*处理结果|//\s*TODO[^:]" {file} # 必须命中 0 次
1566
+ grep -E "errorMessage|alert|toast" {file} # 每个 .failure 块至少 1 处
1567
+ ```
1568
+ - **绕过条件**:无。"先占位以后补"的代码示例 = 永远不会补的代码示例
71
1569
 
72
- **简单判断**:先问自己「这个 slice 以后能被几个 scenario 引用?」——
73
- - 答得出 ≥2 个具体场景 → 独立 slice
74
- - 答不出、或只想得到一个 → 合并回去
75
- - 答不出但概念极独立、未来明显会被复用 → 可破例单拆,但要在 slice 开头写明「当前仅 X 场景使用,预留给 Y、Z 场景」
1570
+ ---
76
1571
 
77
- ### 粒度对比示例
1572
+ ##### 调用时序 [条件必填:多角色异步交互 或 回调嵌套 ≥3 层]
1573
+
1574
+ ###### 触发条件
1575
+ 满足以下任一即必填:
1576
+ - 涉及 ≥2 个角色(如主播 + 观众)的异步交互
1577
+ - 回调嵌套深度 ≥3 层
1578
+ - 状态机分支 ≥3 个
1579
+
1580
+ 不满足 → 整段删除。
1581
+
1582
+ ###### 写作模板
1583
+ ```markdown
1584
+ ## 调用时序
1585
+
1586
+ ```
1587
+ 观众端 SDK 主播端
1588
+ │ │
1589
+ ├─ applyForSeat ──→ │
1590
+ │ │
1591
+ │ ←─ onApplication ─┤
1592
+ │ │
1593
+ │ ←─ approve ──────┤
1594
+ │ │
1595
+ ├─ {打开摄像头/麦克风} │
1596
+ │ │
1597
+ ```
1598
+ ```
1599
+
1600
+ ###### 必填项语义三件套
1601
+ - **违反后果**:多角色交互无时序图 → AI 生成代码角色行为错位 → 上线后双方互相听不到
1602
+ - **验证手段**:人工 review,触发条件命中即必有;时序图覆盖所有角色和关键事件
1603
+ - **绕过条件**:不满足触发条件 → 可省
1604
+
1605
+ ---
1606
+
1607
+ ##### 平台特有注意事项 [必填:至少 1 条]
1608
+
1609
+ ###### 1️⃣ 你必须写什么
1610
+ 仅在该平台才会踩的坑。每条标准:**该平台独有 + 不写出来研发会踩**。
1611
+
1612
+ 跨平台通用的注意事项 → 上移到产品级概览的 ALWAYS/NEVER。
1613
+
1614
+ ###### 2️⃣ 写作模板
1615
+ ```markdown
1616
+ ## 平台特有注意事项
1617
+
1618
+ - **{该平台特有的现象/约束}** —— {为什么会发生}。
1619
+ 必须做:{具体动作}。
1620
+ ```
78
1621
 
79
- 以「消息」为例:
1622
+ ###### 3️⃣ ✅ 正例(iOS)
1623
+ ```markdown
1624
+ ## 平台特有注意事项
1625
+
1626
+ - **`AnyCancellable` 必须存为实例属性,不能存为局部变量** —— 局部变量出
1627
+ 作用域后 cancellable 被释放,sink 闭包永远不会触发。
1628
+ 必须做:声明 `private var cancellables = Set<AnyCancellable>()` 实例属性,
1629
+ 调用 `.store(in: &cancellables)`。
80
1630
 
1631
+ - **`sink { [weak self] }` 必须显式写 `[weak self]`** —— 不写会导致
1632
+ ViewModel 与 publisher 循环引用,VC 销毁后 ViewModel 不释放。
1633
+ 必须做:所有 `.sink { }` 闭包第一行都加 `[weak self]`。
1634
+
1635
+ - **首次申请麦克风权限的弹窗在异步线程触发会被忽略** —— 必须在主线程
1636
+ 调用 `applyForSeat`,否则系统不展示权限弹窗、SDK 报权限拒绝。
1637
+ 必须做:`DispatchQueue.main.async { applyForSeat() }`。
81
1638
  ```
82
- ❌ 太粗 → 一个"消息"slice 包含发送+接收+历史+撤回+转发+已读+推送
83
- 问题:客户说"消息收不到",要在几千字里找相关部分
84
1639
 
85
- 太细 把发文本消息、发图片、发视频、发文件各做一个 slice
86
- 问题:它们的用法和排障方式几乎一样,重复内容太多
1640
+ ###### 4️⃣ 反例
1641
+ ```markdown
1642
+ ## 平台特有注意事项
87
1643
 
88
- 合适 → 拆成:发送消息 / 接收消息 / 历史消息 / 消息撤回 / 离线推送
89
- 每个都能一次讲清,排查方向各不相同
1644
+ - 注意内存管理。
1645
+ - iOS 上需要权限。
1646
+ - 异步代码要小心。
90
1647
  ```
91
1648
 
1649
+ 为什么这是反例:
1650
+ - ❌ "注意""小心" = 软词
1651
+ - ❌ "内存管理"/"权限"/"异步" = 模糊,跨平台都有
1652
+ - ❌ 没说具体怎么做
1653
+ - → review 直接打回
1654
+
1655
+ ###### 5️⃣ 必填项语义三件套
1656
+ - **违反后果**:平台特有坑没写 → AI 生成代码在该平台报错 / 行为异常 / 内存泄漏
1657
+ - **验证手段**:每条必须含"必须做:{具体动作}";描述的现象其他平台不会出现
1658
+ - **绕过条件**:无
1659
+
92
1660
  ---
1661
+ | **可编译** | 含完整 import、完整类/函数闭包,不允许 `...` 省略任何逻辑分支 |
1662
+ | **可运行** | 补充业务参数后可直接跑通;业务参数用 `{TODO: 填入 xxx}` 占位 |
1663
+ | **有日志锚点** | 关键路径(申请发送成功、主播同意、设备打开、失败分支)必须有 `print`/`console.log`/`Log.d`,带模块前缀如 `[CoGuest]` |
1664
+ | **有错误处理** | 每个 `.failure` / `catch` / `error` 分支必须有面向用户的处理(UI 可见的 `errorMessage` 或 `alert`),不允许只 `print` |
1665
+ | **多角色分开写** | 主播端 / 观众端这种异构角色,**必须**拆成独立示例代码块 |
1666
+ | **可组合性** | 对外暴露清晰输入/输出;依赖用注释标注 `// 前置:登录完成(→ live/login-auth)` |
1667
+
1668
+ ###### 3️⃣ 写作模板(以 iOS Swift 为例)
1669
+ ````markdown
1670
+ ### 场景 X:{场景名,如"观众发起连麦申请"}
1671
+
1672
+ ```swift
1673
+ // 前置:登录完成(→ chat/login-auth)
1674
+ // 前置:已加入房间(→ live/room-lifecycle)
1675
+
1676
+ import TencentImSDKPlugin
1677
+ import Combine
1678
+
1679
+ class CoGuestApplyViewModel: ObservableObject {
1680
+ @Published var errorMessage: String? // ← UI 必需,展示给用户
1681
+ private var cancellables = Set<AnyCancellable>()
1682
+
1683
+ func applyForSeat() {
1684
+ print("[CoGuest] 开始发起连麦申请") // ← 日志锚点(供验证矩阵层级 3)
1685
+
1686
+ CoGuestStore.shared.applyForSeat(timeout: 30)
1687
+ .sink { [weak self] completion in // ← [weak self] 必需
1688
+ if case .failure(let error) = completion {
1689
+ print("[CoGuest] 申请失败: \(error)")
1690
+ self?.errorMessage = "连麦申请失败,请重试" // ← 用户可见
1691
+ }
1692
+ } receiveValue: { [weak self] _ in
1693
+ print("[CoGuest] 申请已发送")
1694
+ self?.errorMessage = nil
1695
+ }
1696
+ .store(in: &cancellables)
1697
+ }
1698
+ }
1699
+ ```
1700
+ ````
1701
+
1702
+ ###### 4️⃣ ❌ 反例
1703
+ ```swift
1704
+ // 反例 1:用 ... 省略
1705
+ func applyForSeat() {
1706
+ CoGuestStore.shared.applyForSeat(...) { result in
1707
+ // 处理结果
1708
+ ...
1709
+ }
1710
+ }
1711
+ // → "..." 跳过了失败处理 → AI 学到这个模式后到处省略
1712
+
1713
+ // 反例 2:仅 print 错误
1714
+ .sink { completion in
1715
+ if case .failure(let error) = completion {
1716
+ print("error: \(error)") // ← 用户看不到!
1717
+ }
1718
+ }
1719
+ // → 客户线上故障时用户只看到无反应
1720
+
1721
+ // 反例 3:省略 import
1722
+ class XXX {
1723
+ var cancellables = Set<AnyCancellable>()
1724
+ // ↑ 没 import Combine,代码贴出来不能编译
1725
+ }
1726
+
1727
+ // 反例 4:业务参数瞎编
1728
+ applyForSeat(seatIndex: 1, timeout: 60, reason: "我想连麦")
1729
+ // → "我想连麦" 应该用 {TODO: 填入业务申请理由} 占位
1730
+
1731
+ // 反例 5:多角色塞一个类里
1732
+ class CoGuestManager {
1733
+ func audienceApply() { ... }
1734
+ func hostApprove() { ... }
1735
+ }
1736
+ // → 主播观众职责混合,AI 生成时随机抽方法
1737
+ ```
93
1738
 
94
- ## 三、Slice 两层架构:主线 + 反馈
1739
+ ###### 5️⃣ 必填项语义三件套
1740
+ - **违反后果**:含 `...` / 仅 print 错误 / 省略 import → AI 学坏 → 跨 slice 蔓延错误模式 → slice 不可合并,**已合并的批量回退**(2025-03 真实事故,2 周返工)
1741
+ - **验证手段**:
1742
+ ```bash
1743
+ # 1. 抽取代码块编译
1744
+ python scripts/extract_code.py {file} | xcodebuild build ...
1745
+ # 2. 静态扫描
1746
+ grep -E "\.\.\.|//\s*处理结果|//\s*TODO[^:]" {file} # 必须命中 0 次
1747
+ grep -E "errorMessage|alert|toast" {file} # 每个 .failure 块至少 1 处
1748
+ ```
1749
+ - **绕过条件**:无。"先占位以后补"的代码示例 = 永远不会补的代码示例
95
1750
 
96
- | 层级 | 名称 | 来源 | 用途 |
97
- |------|------|------|------|
98
- | 🅰️ **主线 Slice** | 骨架 | 按 SDK 能力域系统规划(来自官方文档+研发经验) | 保证每个核心功能都有覆盖 |
99
- | 🅱️ **反馈 Slice** | 血肉 | 从产品/销售收集的用户高频问题中提炼 | 补充真实的坑和边缘场景 |
1751
+ ---
100
1752
 
101
- ### 两者的关系
102
- - **主线是骨架**:每个开发者都要走的路(初始化 → 登录 → 发消息 → ...)
103
- - **反馈是血肉**:开发者最容易摔跤的坑(互踢死循环、推送不到达、...)
104
- - 反馈 slice 可以是主线 slice 的深度补充,也可以是全新的边缘场景
1753
+ ##### 调用时序 [条件必填:多角色异步交互 或 回调嵌套 ≥3 层]
105
1754
 
106
- ### 在 index.yaml 中的标记
1755
+ ###### 触发条件
1756
+ 满足以下任一即必填:
1757
+ - 涉及 ≥2 个角色(如主播 + 观众)的异步交互
1758
+ - 回调嵌套深度 ≥3 层
1759
+ - 状态机分支 ≥3 个
1760
+
1761
+ 不满足 → 整段删除。
1762
+
1763
+ ###### 写作模板
1764
+ ```markdown
1765
+ ## 调用时序
107
1766
 
108
- ```yaml
109
- - id: chat/multi-instance
110
- name: 多端登录与互踢
111
- tags: [multi-instance, kick-offline, login]
112
- platforms: [web, android, ios, flutter]
113
- file: slices/chat/multi-instance.md
114
- description: 多端登录策略配置、互踢回调处理、常见错误码
115
- status: active # active | planned
1767
+ ```
1768
+ 观众端 SDK 主播端
1769
+ │ │
1770
+ ├─ applyForSeat ──→ │
1771
+ │ │
1772
+ │ ←─ onApplication ─┤
1773
+ │ │
1774
+ │ ←─ approve ──────┤
1775
+ │ │
1776
+ ├─ {打开摄像头/麦克风} │
1777
+ │ │
1778
+ ```
116
1779
  ```
117
1780
 
1781
+ ###### 必填项语义三件套
1782
+ - **违反后果**:多角色交互无时序图 → AI 生成代码角色行为错位 → 上线后双方互相听不到
1783
+ - **验证手段**:人工 review,触发条件命中即必有;时序图覆盖所有角色和关键事件
1784
+ - **绕过条件**:不满足触发条件 → 可省
1785
+
118
1786
  ---
119
1787
 
120
- ## 四、Slice 文件结构规范
1788
+ ##### 平台特有注意事项 [必填:至少 1 条]
121
1789
 
122
- 每个 slice 文件是一个 Markdown 文件,包含 YAML frontmatter 和固定的内容结构。
1790
+ ###### 1️⃣ 你必须写什么
1791
+ 仅在该平台才会踩的坑。每条标准:**该平台独有 + 不写出来研发会踩**。
123
1792
 
124
- ### 文件位置
1793
+ 跨平台通用的注意事项 → 上移到产品级概览的 ALWAYS/NEVER。
1794
+
1795
+ ###### 2️⃣ 写作模板
1796
+ ```markdown
1797
+ ## 平台特有注意事项
125
1798
 
1799
+ - **{该平台特有的现象/约束}** —— {为什么会发生}。
1800
+ 必须做:{具体动作}。
126
1801
  ```
127
- knowledge-base/slices/{product}/{ability}.md # 产品级概览(跨平台通用)
128
- knowledge-base/slices/{product}/{platform}/{ability}.md # 平台实现细节
1802
+
1803
+ ###### 3️⃣ ✅ 正例(iOS)
1804
+ ```markdown
1805
+ ## 平台特有注意事项
1806
+
1807
+ - **`AnyCancellable` 必须存为实例属性,不能存为局部变量** —— 局部变量出
1808
+ 作用域后 cancellable 被释放,sink 闭包永远不会触发。
1809
+ 必须做:声明 `private var cancellables = Set<AnyCancellable>()` 实例属性,
1810
+ 调用 `.store(in: &cancellables)`。
1811
+
1812
+ - **`sink { [weak self] }` 必须显式写 `[weak self]`** —— 不写会导致
1813
+ ViewModel 与 publisher 循环引用,VC 销毁后 ViewModel 不释放。
1814
+ 必须做:所有 `.sink { }` 闭包第一行都加 `[weak self]`。
1815
+
1816
+ - **首次申请麦克风权限的弹窗在异步线程触发会被忽略** —— 必须在主线程
1817
+ 调用 `applyForSeat`,否则系统不展示权限弹窗、SDK 报权限拒绝。
1818
+ 必须做:`DispatchQueue.main.async { applyForSeat() }`。
129
1819
  ```
130
1820
 
131
- > **平台实现文件模板**:新建平台 slice 时,请复制 [`platform-slice-template.md`](platform-slice-template.md) 并按批注填写。填写范例见 `slices/live/ios/coguest-apply.md`。
1821
+ ###### 4️⃣ 反例
1822
+ ```markdown
1823
+ ## 平台特有注意事项
132
1824
 
133
- ### Section 标签约定
1825
+ - 注意内存管理。
1826
+ - iOS 上需要权限。
1827
+ - 异步代码要小心。
1828
+ ```
134
1829
 
135
- 每个 section 标题后面统一标注三种标签之一,研发写的时候一眼知道要不要填:
1830
+ 为什么这是反例:
1831
+ - ❌ "注意""小心" = 软词
1832
+ - ❌ "内存管理"/"权限"/"异步" = 模糊,跨平台都有
1833
+ - ❌ 没说具体怎么做
1834
+ - → review 直接打回
136
1835
 
137
- | 标签 | 含义 | 省略规则 |
138
- |------|------|---------|
139
- | `[必填]` | 必须写,否则 slice 不合格 | 不可省 |
140
- | `[可选]` | 视情况写,不影响合格 | 可整段删除 |
141
- | `[条件必填:<触发条件>]` | 满足条件时必须写,不满足时可省 | 不满足时可整段删除 |
1836
+ ###### 5️⃣ 必填项语义三件套
1837
+ - **违反后果**:平台特有坑没写 → AI 生成代码在该平台报错 / 行为异常 / 内存泄漏
1838
+ - **验证手段**:每条必须含"必须做:{具体动作}";描述的现象其他平台不会出现
1839
+ - **绕过条件**:无
1840
+
1841
+ ---
1842
+
1843
+ ##### 代码生成约束 [必填]
1844
+
1845
+ 此 section 是给 AI 读的硬性规则。**只有 apply 能机械验证的规则才能进 MUST/MUST NOT**。
1846
+ 此 section 是给 AI 读的硬性规则。**只有 apply 能机械验证的规则才能进 MUST/MUST NOT**。
1847
+
1848
+ ###### 编译必要条件 [必填]
1849
+ ###### 编译必要条件 [必填]
142
1850
 
143
- 示例:
144
1851
  ```markdown
145
- ## 功能说明 [必填]
146
- ## 调用时序 [条件必填:异步回调嵌套 ≥3 层 或 涉及 3 个及以上角色]
147
- ## 关联知识 [可选]
1852
+ ### 编译必要条件
1853
+
1854
+ - **必须导入** `{包名 1}` / `{包名 2}` —— SDK 类型不可用则编译失败。
1855
+ - **最低 SDK 版本**:`{version}`(若高于 base-setup 中的版本)
1856
+ - **必须的权限声明**:
1857
+ - iOS: Info.plist `{key}` —— {用途}
1858
+ - Android: Manifest `{permission}` —— {用途}
148
1859
  ```
149
1860
 
150
- ### Frontmatter 字段
1861
+ **正例**:
1862
+ ```markdown
1863
+ ### 编译必要条件
1864
+
1865
+ - **必须导入** `import TencentImSDKPlugin` 与 `import Combine`
1866
+ - **最低 iOS 版本**:`13.0`(Combine 最低要求)
1867
+ - **必须的权限声明**:
1868
+ - Info.plist `NSMicrophoneUsageDescription` —— 连麦需要麦克风
1869
+ - Info.plist `NSCameraUsageDescription` —— 连麦需要摄像头
1870
+ ```
1871
+
1872
+ ❌ **反例**:
1873
+ ```markdown
1874
+ - 需要导入相关的包。
1875
+ - 最低版本参见官方文档。
1876
+ - 注意申请权限。
1877
+ ```
1878
+ → 模糊、不可机械验证、`参见官方文档` = 等于没写
151
1879
 
152
- ```yaml
153
1880
  ---
154
- id: chat/msg-send # [必填] Slice ID,与 index.yaml 中的 id 一致
155
- name: 发送消息 # [必填] Slice 名称
156
- product: chat # [必填] 所属产品
157
- tags: [message, send, ...] # [必填] 搜索标签,至少 3 个
158
- platforms: [web, android, ios, flutter] # [必填] 支持的平台
159
- related: # [可选] 关联的 slice,没有则省略此字段
160
- - chat/msg-receive
161
- - chat/msg-custom
1881
+
1882
+ ###### MUST(生成时必须包含) [必填,至少 3 条]
1883
+
1884
+ ####### 1️⃣ 你必须写什么
1885
+ MUST AI 生成代码时**机械验证**的硬约束,**只写 apply 能用 grep 验的规则**。
1886
+ > **MUST 的语义 = backtick 符号能验的语义**。规则文字不能比 backtick 承诺得更多。
1887
+
1888
+ ####### 2️⃣ 写作模板
1889
+ ```markdown
1890
+ #### MUST
1891
+
1892
+ 1. **必须 {强动词} `{可 grep 的符号}`** —— {不这样做的具体后果}。
1893
+ **Verify**: 检查 `{符号}` 出现 ≥1 次。
1894
+ ### 编译必要条件
1895
+
1896
+ - **必须导入** `{包名 1}` / `{包名 2}` —— SDK 类型不可用则编译失败。
1897
+ - **最低 SDK 版本**:`{version}`(若高于 base-setup 中的版本)
1898
+ - **必须的权限声明**:
1899
+ - iOS: Info.plist `{key}` —— {用途}
1900
+ - Android: Manifest `{permission}` —— {用途}
1901
+ ```
1902
+
1903
+ ✅ **正例**:
1904
+ ```markdown
1905
+ ### 编译必要条件
1906
+
1907
+ - **必须导入** `import TencentImSDKPlugin` 与 `import Combine`
1908
+ - **最低 iOS 版本**:`13.0`(Combine 最低要求)
1909
+ - **必须的权限声明**:
1910
+ - Info.plist `NSMicrophoneUsageDescription` —— 连麦需要麦克风
1911
+ - Info.plist `NSCameraUsageDescription` —— 连麦需要摄像头
1912
+ ```
1913
+
1914
+ ❌ **反例**:
1915
+ ```markdown
1916
+ - 需要导入相关的包。
1917
+ - 最低版本参见官方文档。
1918
+ - 注意申请权限。
1919
+ ```
1920
+ → 模糊、不可机械验证、`参见官方文档` = 等于没写
1921
+
162
1922
  ---
1923
+
1924
+ ###### MUST(生成时必须包含) [必填,至少 3 条]
1925
+
1926
+ ####### 1️⃣ 你必须写什么
1927
+ MUST 是 AI 生成代码时**机械验证**的硬约束,**只写 apply 能用 grep 验的规则**。
1928
+ > **MUST 的语义 = backtick 符号能验的语义**。规则文字不能比 backtick 承诺得更多。
1929
+
1930
+ ####### 2️⃣ 写作模板
1931
+ ```markdown
1932
+ #### MUST
1933
+
1934
+ 1. **必须 {强动词} `{可 grep 的符号}`** —— {不这样做的具体后果}。
1935
+ **Verify**: 检查 `{符号}` 出现 ≥1 次。
1936
+
1937
+ 2. **必须 {强动词} `{符号 A}` 与 `{符号 B}`** —— {后果}。
1938
+ **Verify**: 检查 `{符号 A}` 与 `{符号 B}` 各出现 ≥1 次。
1939
+
1940
+ 3. **必须在 {场景} 时调用 `{符号}`** —— {后果}。
1941
+ **Verify**: 检查 `{符号}` 出现 ≥1 次。
163
1942
  ```
164
1943
 
165
- > **官方文档链接统一放在平台实现文件的 `api_docs` 字段**,产品级概览不放文档链接——因为教程/指南页通常按平台区分,放在跨平台的产品级文件里不合适。
1944
+ > ⚠️ 「在 X 时调用 Y」中的"X"语义 apply **不验**,只验 Y 出现。
1945
+ > 这是有意的——调用时机属于软规则,放到「调用时序」section 引导 AI。
166
1946
 
167
- **平台实现文件的 frontmatter 字段**见「平台实现文件」小节。
1947
+ ####### 3️⃣ ✅ 正例(摘自 chat/ios/multi-instance)
1948
+ ```markdown
1949
+ #### MUST
168
1950
 
169
- ### 内容结构
1951
+ 1. **必须导入 `import TencentImSDKPlugin`** —— 否则 SDK 类型不可用,编译报错。
1952
+ **Verify**: 检查 `import TencentImSDKPlugin` 出现 ≥1 次。
170
1953
 
171
- #### 产品级概览(`{product}/{ability}.md`)
1954
+ 2. **必须注册互踢监听 `addSimpleMsgListener`** —— 不注册则用户被踢后无感知。
1955
+ **Verify**: 检查 `addSimpleMsgListener` 出现 ≥1 次。
172
1956
 
173
- 产品级概览是**跨平台通用**的,描述的是"做什么"和"为什么",不涉及"怎么做"。
1957
+ 3. **必须在 `onKickedOffline` 回调里展示 UI 反馈 `errorMessage`** ——
1958
+ 仅 print 不算,用户看不到。
1959
+ **Verify**: 检查 `onKickedOffline` 与 `errorMessage` 各出现 ≥1 次。
1960
+ ```
174
1961
 
175
- **平台无关性规则**:
1962
+ 为什么这是正例:
1963
+ - ✅ 每条都用强动词("必须导入""必须注册"),不用"应该""建议"
1964
+ - ✅ backtick 内是**精确的可 grep 字符串**(类名/方法名)
1965
+ - ✅ 规则文字承诺的范围 ≤ Verify 能验的范围(无维度溢出)
1966
+ - ✅ 每条都有"违反后果"
176
1967
 
177
- | 可以出现 | 不可以出现 |
178
- |-------------|-------------|
179
- | 操作语义("观众发起连麦申请") | 具体 API 签名(`applyForSeat(seatIndex:timeout:)` 这种 Swift 命名参数风格) |
180
- | 通用概念名("连麦管理器"、"事件流") | 平台特有类名/机制(`PassthroughSubject`、`ViewController`、`cancellable`) |
181
- | 行为级最佳实践("通过前不要开设备") | 代码结构级约束("`[weak self]` 避免循环引用") |
182
- | 通用排障逻辑("检查主播端是否订阅了事件") | 平台特有排障("检查 cancellable 是否被提前释放") |
183
- | 跨平台统一的错误码 | 仅某平台出现的错误码或异常行为 |
1968
+ ####### 4️⃣反例
1969
+ ```markdown
1970
+ #### MUST
1971
+
1972
+ 1. **应该正确处理互踢回调** —— 否则用户体验不好。
1973
+ **Verify**: 检查互踢逻辑是否完整。
1974
+ 软词"应该" + 模糊动词"处理" + Verify 不可机械化
1975
+
1976
+ 2. **必须调用 `login()` 或 `loginWithSig()`** —— 没登录无法用 SDK。
1977
+ **Verify**: 检查 `login` 出现。
1978
+ ↑ "或" = 红旗词;只 grep 一个 ≠ 验了选择
1979
+
1980
+ 3. **必须按业务场景选择互踢策略** —— 业务决定。
1981
+ **Verify**: 检查策略配置是否合理。
1982
+ ↑ "按业务""合理" = 不可机械验证,应下沉到「最佳实践」软规则
1983
+ ```
1984
+
1985
+ 为什么这是反例:
1986
+ - ❌ 反例 1:用"应该""处理"等软词 → AI 视作可选
1987
+ - ❌ 反例 2:含红旗词"或" → 维度溢出
1988
+ - ❌ 反例 3:含"按业务""合理" → 不可机械验证,会训练 AI 凑字符串
1989
+ - → review 时**任何一条 MUST 含红旗词,整张 PR 打回**
1990
+
1991
+ ####### 5️⃣ 必填项语义三件套
1992
+ - **违反后果**:MUST 含红旗词("或/任一/等价/按业务/根据场景/留给/负责")→ apply 误杀正确代码 + 训练 AI 凑字符串 → slice 不可合并(2024-12 真实事故:room-lifecycle 写"调 A 或 B",apply 验过却生成错误混合代码)
1993
+ - **验证手段**:
1994
+ ```bash
1995
+ python scripts/check_must_rules.py {file}
1996
+ # 通过标准:红旗词命中 0 次;每条 MUST 都有 Verify;Verify 内有 backtick
1997
+ ```
1998
+ - **绕过条件**:无。MUST 是硬约束区,不接受任何豁免。需要"或/按业务"语义 → 拆原子规则,或下沉到「最佳实践」软规则区
1999
+
2000
+ ---
184
2001
 
185
- **核心概念表的写法**:用操作名 + 语义描述,不写某个平台的方法签名。如果各平台 API 完全一致(同名同参数),可以写通用签名;如果有差异,只写操作语义,具体签名放到平台文件。
2002
+ ###### MUST NOT(生成时绝不能出现) [必填,至少 2 条]
186
2003
 
187
- **自查方法**:把文件中所有 API 名、类名、术语逐一检查 — 如果一个 Android 开发者读到它会觉得困惑或不适用,那就是平台特有内容,应该下沉到平台文件。
2004
+ ####### 1️⃣ 你必须写什么
2005
+ 列出**绝不允许出现**的代码模式。同样要求 backtick 可 grep。
188
2006
 
2007
+ ####### 2️⃣ 写作模板
189
2008
  ```markdown
190
- # {名称}(产品级概览)
2009
+ #### MUST NOT
191
2010
 
192
- ## 功能说明 [必填]
193
- [功能描述、典型场景、版本要求]
2011
+ 1. **不要 {动作} `{符号}`** —— {违反后果}。
2012
+ **Verify**: 检查 `{符号}` 出现 0 次。
2013
+ ```
194
2014
 
195
- ## 核心概念 [必填]
196
- [操作语义 + 状态机 + 角色关系,不含平台特有 API 签名]
2015
+ ####### 3️⃣ ✅ 正例
2016
+ ```markdown
2017
+ #### MUST NOT
197
2018
 
198
- ## 最佳实践 [必填]
199
- ### ✅ ALWAYS(必须做的)
200
- [行为级规则:描述"该做什么",不指定"用哪个 API 做"]
201
- ### ❌ NEVER(绝不要做的)
202
- [行为级规则:描述"不该做什么",不指定平台实现细节]
2019
+ 1. **不要在 `onKickedOffline` 回调里调用 `login()`** —— 自动重登形成
2020
+ 两端死循环互踢,最终两端都登不上。
2021
+ **Verify**: `onKickedOffline` 函数体内,`login` 出现 0 次。
203
2022
 
204
- ## 排障指南 [必填]
205
- ### 常见错误码
206
- [跨平台统一的错误码表格]
207
- ### 排障流程
208
- [通用排障逻辑树,平台特有分支标注 → 见平台文件]
2023
+ 2. **不要在客户端代码里硬编码 `SecretKey`** —— 密钥泄露后可签发任意 UserSig。
2024
+ **Verify**: 全文 `SecretKey` 出现 0 次。
209
2025
 
210
- ## 关联知识 [可选]
211
- [引用相关 slice;如果没有关联,删除整个 section]
2026
+ 3. **不要用 `try?` 吞掉 `loginWithSig` 的错误** —— 静默失败导致后续 API 调用
2027
+ 全部失败但无日志可查。
2028
+ **Verify**: `try?\s+.*loginWithSig` 出现 0 次(用 grep -E)。
212
2029
  ```
213
2030
 
214
- **产品级概览中各 section 的必填理由**:
215
- - `功能说明` / `核心概念` — slice 的身份标识,缺失则无法理解这个 slice 是做什么的
216
- - `最佳实践` slice 区别于官方文档的核心价值。如果仅抄 API 说明,无需做 slice
217
- - `排障指南` — slice 面向集成场景的交付标准。至少给出「常见错误码」和「排障流程」两个子项,否则客户报问题时无章可循
218
- - `关联知识` — 孤立能力可省。有 2+ 相关 slice 时必须写,防止知识孤岛
2031
+ 为什么这是正例:
2032
+ - 每条都精确到"哪个上下文里不能出现哪个符号"
2033
+ - Verify 0 次匹配,机械可验
219
2034
 
220
- > 提交前对照第五节「产品级概览 DoD」逐条打勾,合格后再提交。
2035
+ ####### 4️⃣ ❌ 反例
2036
+ ```markdown
2037
+ #### MUST NOT
221
2038
 
222
- #### 平台实现文件(`{product}/{platform}/{ability}.md`)
2039
+ 1. 不要写不安全的代码。
2040
+ 2. 避免循环引用。
2041
+ 3. 不要忽略错误。
2042
+ ```
2043
+ → 全部模糊,无 backtick,无 Verify
223
2044
 
224
- ##### Frontmatter 字段
2045
+ ####### 5️⃣ 必填项语义三件套
2046
+ - **违反后果**:MUST NOT 缺失或模糊 → AI 生成代码引入安全/性能/稳定性问题
2047
+ - **验证手段**:同 MUST,跑 `check_must_rules.py`
2048
+ - **绕过条件**:无
225
2049
 
226
- ```yaml
227
2050
  ---
228
- id: {product}/{ability} # [必填] 与产品级 slice 的 id 一致
229
- platform: {platform} # [必填] ios / android / web / flutter / electron
230
- api_docs: # [必填] 该平台 API 参考文档链接(至少 1 条)
231
- - title: {API 类名/模块名}
232
- url: https://...
2051
+
2052
+ ###### 集成检查点 [必填]
2053
+
2054
+ ```markdown
2055
+ ### 集成检查点
2056
+
2057
+ - 是否与项目已有 SDK 初始化冲突?(检查 `{初始化函数}` 是否已在别处调用)
2058
+ - 是否依赖其他 slice 的前置状态?(本 slice 依赖 → `{slice-id}`)
2059
+ - 对已有代码的侵入性:`{新增 X 个文件 / 修改 Y 个文件}`
2060
+ ```
2061
+
2062
+ ✅ **正例**:
2063
+ ```markdown
2064
+ ### 集成检查点
2065
+
2066
+ - 是否与项目已有 SDK 初始化冲突?检查项目中 `V2TIMManager.sharedInstance().initSDK()`
2067
+ 是否已被调用,若是则不要重复调用
2068
+ - 是否依赖其他 slice?依赖 `chat/login-auth` 完成登录
2069
+ - 对已有代码的侵入性:新增 1 个 ViewModel 文件,无需修改现有代码
2070
+ ```
2071
+
2072
+ ###### 必填项语义三件套(集成检查点)
2073
+ - **违反后果**:不写检查点 → 集成时与已有代码冲突(双重初始化、状态污染)
2074
+ - **验证手段**:必须有 ≥3 条;每条引用具体函数/slice/文件数
2075
+ - **绕过条件**:无
2076
+
233
2077
  ---
2078
+
2079
+ ###### MUST 规则的维度对齐原则 [必填阅读]
2080
+ 2. **必须 {强动词} `{符号 A}` 与 `{符号 B}`** —— {后果}。
2081
+ **Verify**: 检查 `{符号 A}` 与 `{符号 B}` 各出现 ≥1 次。
2082
+
2083
+ 3. **必须在 {场景} 时调用 `{符号}`** —— {后果}。
2084
+ **Verify**: 检查 `{符号}` 出现 ≥1 次。
234
2085
  ```
235
2086
 
236
- **`api_docs` 填写质量要求**:
2087
+ > ⚠️ 「在 X 时调用 Y」中的"X"语义 apply **不验**,只验 Y 出现。
2088
+ > 这是有意的——调用时机属于软规则,放到「调用时序」section 引导 AI。
237
2089
 
238
- | 要求 | 说明 | 举例 |
239
- |------|------|------|
240
- | ✅ 精确到**类/模块**级 | 一条链接打开就能看到本 slice 涉及的具体类 API | `https://tencent-rtc.github.io/TUIKit_iOS/documentation/atomicxcore/cogueststore/` |
241
- | ✅ 多个类的 slice 可多条 | 一个 slice 涉及多个 Store/Manager 时分别列出 | `CoGuestStore` + `DeviceStore` |
242
- | ❌ 不要填 SDK 首页 | 首页没有具体类签名,AI 拿不到校验所需信息 | `https://trtc.io/sdk` |
243
- | ❌ 不要填产品级教程页 | 教程/指南页不属于 API 参考 | `https://trtc.io/zh/document/74598` |
2090
+ ####### 3️⃣ 正例(摘自 chat/ios/multi-instance)
2091
+ ```markdown
2092
+ #### MUST
244
2093
 
245
- **若该平台没有可用的 API 参考页**(如 Electron/Unity 某些模块):
246
- - 优先考虑这个 slice 在该平台是否真的需要独立文件
247
- - 若确需保留,填入**头文件/类型声明文件**的 GitHub 永久链接(commit hash 固定版本),而不是空链接
2094
+ 1. **必须导入 `import TencentImSDKPlugin`** —— 否则 SDK 类型不可用,编译报错。
2095
+ **Verify**: 检查 `import TencentImSDKPlugin` 出现 ≥1 次。
248
2096
 
249
- > 注:`name` / `tags` / `platforms` / `related` 在产品级概览中维护,平台文件不重复。
2097
+ 2. **必须注册互踢监听 `addSimpleMsgListener`** —— 不注册则用户被踢后无感知。
2098
+ **Verify**: 检查 `addSimpleMsgListener` 出现 ≥1 次。
250
2099
 
251
- ##### 内容结构
2100
+ 3. **必须在 `onKickedOffline` 回调里展示 UI 反馈 `errorMessage`** ——
2101
+ 仅 print 不算,用户看不到。
2102
+ **Verify**: 检查 `onKickedOffline` 与 `errorMessage` 各出现 ≥1 次。
2103
+ ```
252
2104
 
253
- 平台实现文件按以下结构编写,每个 section 标题后都必须带必填/可选标签:
2105
+ 为什么这是正例:
2106
+ - ✅ 每条都用强动词("必须导入""必须注册"),不用"应该""建议"
2107
+ - ✅ backtick 内是**精确的可 grep 字符串**(类名/方法名)
2108
+ - ✅ 规则文字承诺的范围 ≤ Verify 能验的范围(无维度溢出)
2109
+ - ✅ 每条都有"违反后果"
254
2110
 
2111
+ ####### 4️⃣ ❌ 反例
255
2112
  ```markdown
256
- # {名称} — {平台} 实现
2113
+ #### MUST
257
2114
 
258
- ## 前置条件 [必填]
259
- ## 代码示例 [必填]
260
- ## 调用时序 [条件必填:多角色异步交互 回调嵌套 ≥3 层]
261
- ## 平台特有注意事项 [必填:至少 1 条]
262
- ## 代码生成约束 [必填]
263
- ## 验证矩阵 [必填]
2115
+ 1. **应该正确处理互踢回调** —— 否则用户体验不好。
2116
+ **Verify**: 检查互踢逻辑是否完整。
2117
+ 软词"应该" + 模糊动词"处理" + Verify 不可机械化
2118
+
2119
+ 2. **必须调用 `login()` 或 `loginWithSig()`** —— 没登录无法用 SDK。
2120
+ **Verify**: 检查 `login` 出现。
2121
+ ↑ "或" = 红旗词;只 grep 一个 ≠ 验了选择
2122
+
2123
+ 3. **必须按业务场景选择互踢策略** —— 业务决定。
2124
+ **Verify**: 检查策略配置是否合理。
2125
+ ↑ "按业务""合理" = 不可机械验证,应下沉到「最佳实践」软规则
264
2126
  ```
265
2127
 
266
- 各 section 详细要求见下方。
2128
+ 为什么这是反例:
2129
+ - ❌ 反例 1:用"应该""处理"等软词 → AI 视作可选
2130
+ - ❌ 反例 2:含红旗词"或" → 维度溢出
2131
+ - ❌ 反例 3:含"按业务""合理" → 不可机械验证,会训练 AI 凑字符串
2132
+ - → review 时**任何一条 MUST 含红旗词,整张 PR 打回**
2133
+
2134
+ ####### 5️⃣ 必填项语义三件套
2135
+ - **违反后果**:MUST 含红旗词("或/任一/等价/按业务/根据场景/留给/负责")→ apply 误杀正确代码 + 训练 AI 凑字符串 → slice 不可合并(2024-12 真实事故:room-lifecycle 写"调 A 或 B",apply 验过却生成错误混合代码)
2136
+ - **验证手段**:
2137
+ ```bash
2138
+ python scripts/check_must_rules.py {file}
2139
+ # 通过标准:红旗词命中 0 次;每条 MUST 都有 Verify;Verify 内有 backtick
2140
+ ```
2141
+ - **绕过条件**:无。MUST 是硬约束区,不接受任何豁免。需要"或/按业务"语义 → 拆原子规则,或下沉到「最佳实践」软规则区
267
2142
 
268
- ##### 代码示例标准 [必填]
2143
+ ---
269
2144
 
270
- 平台 slice 的核心交付物。要求:
2145
+ ###### MUST NOT(生成时绝不能出现) [必填,至少 2 条]
271
2146
 
272
- | 维度 | 最低标准 |
273
- |------|---------|
274
- | **可编译** | 包含完整 import、完整类/函数闭包,不允许 `...` 省略任何逻辑分支 |
275
- | **可运行** | 补充业务参数后可直接跑通;业务参数用 `{TODO: 填入 xxx}` 占位,而不是随意编的字符串 |
276
- | **有日志锚点** | 关键路径(申请发送成功、主播同意、设备打开、失败分支)必须有 `print`/`console.log`/`Log.d`,供「验证矩阵」在运行时观察;日志统一带模块前缀如 `[CoGuest]` |
277
- | **有错误处理** | 每一个 `.failure` / `catch` / `error` 分支都必须有面向用户的处理(UI 可见的 `errorMessage` 或 `alert`),不允许只 `print` 就结束 |
278
- | **多角色分开写** | 主播端 / 观众端 这种异构角色,**必须**拆成独立示例代码块 |
279
- | **可组合性** | 对外暴露清晰输入/输出;不硬编码其他 slice 的调用(如登录初始化),依赖用注释标注 `// 前置:登录完成(→ live/login-auth)` |
280
-
281
- **禁止事项**:
282
- - ❌ 用伪代码或 `...` 跳过逻辑
283
- - ❌ 把多个 slice 的职责耦合在一个类里
284
- - ❌ 省略失败分支处理
2147
+ ####### 1️⃣ 你必须写什么
2148
+ 列出**绝不允许出现**的代码模式。同样要求 backtick 可 grep。
285
2149
 
286
- ##### 代码生成约束 [必填]
2150
+ ####### 2️⃣ 写作模板
2151
+ ```markdown
2152
+ #### MUST NOT
2153
+
2154
+ 1. **不要 {动作} `{符号}`** —— {违反后果}。
2155
+ **Verify**: 检查 `{符号}` 出现 0 次。
2156
+ ```
2157
+
2158
+ ####### 3️⃣ ✅ 正例
2159
+ ```markdown
2160
+ #### MUST NOT
2161
+
2162
+ 1. **不要在 `onKickedOffline` 回调里调用 `login()`** —— 自动重登形成
2163
+ 两端死循环互踢,最终两端都登不上。
2164
+ **Verify**: 在 `onKickedOffline` 函数体内,`login` 出现 0 次。
2165
+
2166
+ 2. **不要在客户端代码里硬编码 `SecretKey`** —— 密钥泄露后可签发任意 UserSig。
2167
+ **Verify**: 全文 `SecretKey` 出现 0 次。
287
2168
 
288
- section 是给 AI 读的硬性规则。**只有 apply 能机械验证的规则才能进 MUST/MUST NOT**——具体什么样的规则算「能机械验证」,见下一节「MUST 规则的维度对齐原则」,必读。
2169
+ 3. **不要用 `try?` 吞掉 `loginWithSig` 的错误** —— 静默失败导致后续 API 调用
2170
+ 全部失败但无日志可查。
2171
+ **Verify**: `try?\s+.*loginWithSig` 出现 0 次(用 grep -E)。
2172
+ ```
289
2173
 
290
- 格式示例:
2174
+ 为什么这是正例:
2175
+ - ✅ 每条都精确到"哪个上下文里不能出现哪个符号"
2176
+ - ✅ Verify 是 0 次匹配,机械可验
291
2177
 
2178
+ ####### 4️⃣ ❌ 反例
292
2179
  ```markdown
293
- ### 编译必要条件 [必填]
294
- - 必须导入的模块/包(精确到包名)
295
- - 最低 SDK 版本(若高于 base)
296
- - 必须的权限声明或配置
2180
+ #### MUST NOT
2181
+
2182
+ 1. 不要写不安全的代码。
2183
+ 2. 避免循环引用。
2184
+ 3. 不要忽略错误。
2185
+ ```
2186
+ → 全部模糊,无 backtick,无 Verify
297
2187
 
298
- ### 生成规则 [必填]
2188
+ ####### 5️⃣ 必填项语义三件套
2189
+ - **违反后果**:MUST NOT 缺失或模糊 → AI 生成代码引入安全/性能/稳定性问题
2190
+ - **验证手段**:同 MUST,跑 `check_must_rules.py`
2191
+ - **绕过条件**:无
299
2192
 
300
- #### MUST(生成时必须包含)
2193
+ ---
301
2194
 
302
- 1. **<动作> `符号`** — <违反后果>。
303
- **Verify**: 检查是否存在 `符号`。
2195
+ ###### 集成检查点 [必填]
304
2196
 
305
- 2. **<动作> `符号 A`** — <违反后果>。
306
- **Verify**: 检查是否存在 `符号 A`。
2197
+ ```markdown
2198
+ ### 集成检查点
307
2199
 
308
- #### MUST NOT(生成时绝不能出现)
2200
+ - 是否与项目已有 SDK 初始化冲突?(检查 `{初始化函数}` 是否已在别处调用)
2201
+ - 是否依赖其他 slice 的前置状态?(本 slice 依赖 → `{slice-id}`)
2202
+ - 对已有代码的侵入性:`{新增 X 个文件 / 修改 Y 个文件}`
2203
+ ```
309
2204
 
310
- 1. **不要 <动作> `符号`** — <违反后果>。
311
- **Verify**: 检查 `符号` 出现 0 次。
2205
+ **正例**:
2206
+ ```markdown
2207
+ ### 集成检查点
312
2208
 
313
- ### 集成检查点 [必填]
314
- - 是否与项目已有 SDK 初始化冲突
315
- - 是否依赖其他 slice 的前置状态(引用具体 slice ID)
316
- - 对已有代码的侵入性(新增 vs 修改)
2209
+ - 是否与项目已有 SDK 初始化冲突?检查项目中 `V2TIMManager.sharedInstance().initSDK()`
2210
+ 是否已被调用,若是则不要重复调用
2211
+ - 是否依赖其他 slice?依赖 `chat/login-auth` 完成登录
2212
+ - 对已有代码的侵入性:新增 1 个 ViewModel 文件,无需修改现有代码
317
2213
  ```
318
2214
 
319
- **关键约束**:
2215
+ ###### 必填项语义三件套(集成检查点)
2216
+ - **违反后果**:不写检查点 → 集成时与已有代码冲突(双重初始化、状态污染)
2217
+ - **验证手段**:必须有 ≥3 条;每条引用具体函数/slice/文件数
2218
+ - **绕过条件**:无
320
2219
 
321
- - 每条 MUST/MUST NOT 的 `**Verify**:` 字段引用的 backtick 符号 = apply 唯一会 grep 的东西
322
- - 规则文字描述的所有判断、选择、等价、条件分支,apply **全部不验**——所以这些不要写进 MUST
323
- - 多 backtick 的规则可以接受,apply 解析为「全部都要出现」(all-of)
2220
+ ---
324
2221
 
325
- ##### MUST 规则的维度对齐原则 [必填阅读]
2222
+ ###### MUST 规则的维度对齐原则 [必填阅读]
326
2223
 
327
- ###### 核心原则
2224
+ ####### 核心原则
2225
+ ####### 核心原则
328
2226
 
329
2227
  > **MUST 规则的语义 = 它的 backtick 符号能验的语义。**
330
2228
  >
331
- > 如果你写的规则文字比 backtick 符号能表达的更多,规则就「维度溢出」了——AI 写对了你 grep 不到,AI 写错了你也 grep 不到,verifier 反而把 AI 推向凑字符串。
2229
+ > 如果你写的规则文字比 backtick 符号能表达的更多,规则就「维度溢出」了——AI 写对了你 grep 不到,AI 写错了你也 grep 不到,verifier 反而把 AI 推向凑字符串。
2230
+ > 如果你写的规则文字比 backtick 符号能表达的更多,规则就「维度溢出」了——AI 写对了你 grep 不到,AI 写错了你也 grep 不到,verifier 反而把 AI 推向凑字符串。
332
2231
 
333
- ###### 红旗词表:以下写法说明 MUST 写错了
2232
+ ####### 红旗词表:以下写法说明 MUST 写错了
2233
+ ####### 红旗词表:以下写法说明 MUST 写错了
334
2234
 
335
2235
  | 红旗词 | 例子 | 为什么是红旗 | 怎么改 |
336
2236
  |---|---|---|---|
337
- | **「或 / 任一」** | "出现 `X` 或 `Y`" | grep 一个 ≠ 验了选择 | 拆两条 MUST 各管一个分支;或把「选哪个」移到「最佳实践」/「场景说明」 |
338
- | **「等价 / 或类似」** | "处理 `ERR_X` 或等价提示" | "等价" 无法机械化,AI 写等价代码 verify 还是 fail | 显式枚举所有可接受的 backtick 写法;或承认是软规则放到「最佳实践」 |
339
- | **「按业务 / 根据场景」** | "按业务目标选 `X` 或 `Y`" | 业务判断不是 grep 能做的事 | 完全移出 MUST。具体场景写到「代码示例」每个场景一段,让 AI 选示例 copy |
340
- | **「留给 / 负责」** | "把 X 留给 slice A,把 Y 留给 slice B" | 架构边界没有任何 grep pattern 能验 | 移到「集成检查点」section,作为 AI 读但 apply 不验的引导文字 |
341
- | **多 backtick 但 Verify 只提一个** | "调 `A()` 后再调 `B()`"Verify 只检查 `A` | A 出现 ≠ 调用顺序对 | 拆两条 MUST 各管一个 API;调用顺序不能机械验,写到「调用时序」section |
342
-
343
- ###### 自查三问(写完每条 MUST 之前问自己)
344
-
345
- 1. backtick 里的符号是不是就是 verify 唯一会做的事?规则文字里的其他词能不能删?
346
- 2. 如果 AI 写**等价但不同写法**的代码,verify 会不会误杀?误杀 = 规则太死,要么拆原子要么降级软规则。
347
- 3. 如果 AI 写**只满足 backtick 字符串但语义错**的代码,verify 会不会放过?放过 = 规则太松,应该拆。
348
-
349
- ###### 软规则 vs 硬约束
2237
+ | **「或 / 任一」** | "出现 `X` 或 `Y`" | grep 一个 ≠ 验了选择 | 拆两条 MUST 各管一个分支;或把「选哪个」移到「最佳实践」/「场景说明」 |
2238
+ | **「等价 / 或类似」** | "处理 `ERR_X` 或等价提示" | "等价" 无法机械化,AI 写等价代码 verify 还是 fail | 显式枚举所有可接受的 backtick 写法;或承认是软规则放到「最佳实践」 |
2239
+ | **「按业务 / 根据场景」** | "按业务目标选 `X` 或 `Y`" | 业务判断不是 grep 能做的事 | 完全移出 MUST。具体场景写到「代码示例」每个场景一段,让 AI 选示例 copy |
2240
+ | **「留给 / 负责」** | "把 X 留给 slice A,把 Y 留给 slice B" | 架构边界没有任何 grep pattern 能验 | 移到「集成检查点」section,作为 AI 读但 apply 不验的引导文字 |
2241
+ | **多 backtick 但 Verify 只提一个** | "调 `A()` 后再调 `B()`",Verify 只检查 `A` | A 出现 ≠ 调用顺序对 | 拆两条 MUST 各管一个 API;调用顺序不能机械验,写到「调用时序」section |
2242
+ | **「或 / 任一」** | "出现 `X` 或 `Y`" | grep 一个 ≠ 验了选择 | 拆两条 MUST 各管一个分支;或把「选哪个」移到「最佳实践」/「场景说明」 |
2243
+ | **「等价 / 或类似」** | "处理 `ERR_X` 或等价提示" | "等价" 无法机械化,AI 写等价代码 verify 还是 fail | 显式枚举所有可接受的 backtick 写法;或承认是软规则放到「最佳实践」 |
2244
+ | **「按业务 / 根据场景」** | "按业务目标选 `X` 或 `Y`" | 业务判断不是 grep 能做的事 | 完全移出 MUST。具体场景写到「代码示例」每个场景一段,让 AI 选示例 copy |
2245
+ | **「留给 / 负责」** | "把 X 留给 slice A,把 Y 留给 slice B" | 架构边界没有任何 grep pattern 能验 | 移到「集成检查点」section,作为 AI 读但 apply 不验的引导文字 |
2246
+ | **多 backtick Verify 只提一个** | "调 `A()` 后再调 `B()`",Verify 只检查 `A` | A 出现 ≠ 调用顺序对 | 拆两条 MUST 各管一个 API;调用顺序不能机械验,写到「调用时序」section |
2247
+
2248
+ ####### 自查三问(写完每条 MUST 之前问自己)
2249
+ ####### 自查三问(写完每条 MUST 之前问自己)
2250
+
2251
+ 1. backtick 里的符号是不是就是 verify 唯一会做的事?规则文字里的其他词能不能删?
2252
+ 2. 如果 AI 写**等价但不同写法**的代码,verify 会不会误杀?误杀 = 规则太死,要么拆原子要么降级软规则。
2253
+ 3. 如果 AI 写**只满足 backtick 字符串但语义错**的代码,verify 会不会放过?放过 = 规则太松,应该拆。
2254
+ 1. backtick 里的符号是不是就是 verify 唯一会做的事?规则文字里的其他词能不能删?
2255
+ 2. 如果 AI 写**等价但不同写法**的代码,verify 会不会误杀?误杀 = 规则太死,要么拆原子要么降级软规则。
2256
+ 3. 如果 AI 写**只满足 backtick 字符串但语义错**的代码,verify 会不会放过?放过 = 规则太松,应该拆。
2257
+
2258
+ ####### 软规则 vs 硬约束
2259
+ ####### 软规则 vs 硬约束
350
2260
 
351
2261
  | 类型 | 写在哪 | apply 行为 | AI 行为 |
352
2262
  |---|---|---|---|
353
- | **硬约束**(MUST/MUST NOT | 「代码生成约束」 | grep backtick,命中失败就 fail | 必须包含/避免符号 |
354
- | **软规则**(业务选择、架构建议、调用顺序、错误处理建议) | 「最佳实践」「集成检查点」「调用时序」「代码示例」 | 不验,仅作为 AI 上下文 | 阅读后自行判断 |
2263
+ | **硬约束**(MUST/MUST NOT) | 「代码生成约束」 | grep backtick,命中失败就 fail | 必须包含/避免符号 |
2264
+ | **软规则**(业务选择、架构建议、调用顺序、错误处理建议) | 「最佳实践」「集成检查点」「调用时序」「代码示例」 | 不验,仅作为 AI 上下文 | 阅读后自行判断 |
2265
+ | **硬约束**(MUST/MUST NOT) | 「代码生成约束」 | grep backtick,命中失败就 fail | 必须包含/避免符号 |
2266
+ | **软规则**(业务选择、架构建议、调用顺序、错误处理建议) | 「最佳实践」「集成检查点」「调用时序」「代码示例」 | 不验,仅作为 AI 上下文 | 阅读后自行判断 |
355
2267
 
356
2268
  > **重要 ≠ 能机械验证。**
357
2269
  >
358
- > 把重要但验不了的规则放进 MUST,会**误杀正确代码 + 训练 AI 凑字符串**——这是 verifier 反向变成攻击面。
2270
+ > 把重要但验不了的规则放进 MUST,会**误杀正确代码 + 训练 AI 凑字符串**——这是 verifier 反向变成攻击面。
2271
+ > 把重要但验不了的规则放进 MUST,会**误杀正确代码 + 训练 AI 凑字符串**——这是 verifier 反向变成攻击面。
359
2272
  >
360
- > 重要但不能机械验证的规则,**写到软规则区,靠 AI 阅读 + 反例代码**来引导。
2273
+ > 重要但不能机械验证的规则,**写到软规则区,靠 AI 阅读 + 反例代码**来引导。
2274
+ > 重要但不能机械验证的规则,**写到软规则区,靠 AI 阅读 + 反例代码**来引导。
361
2275
 
362
- ###### 完整改造示例:room-lifecycle 的失败规则
2276
+ ####### 完整改造示例:room-lifecycle 的失败规则
2277
+ ####### 完整改造示例:room-lifecycle 的失败规则
363
2278
 
364
- **改前**(现状写法,触发 AI 凑字符串):
2279
+ **改前**(现状写法,触发 AI 凑字符串):
2280
+ ❌ **改前**(现状写法,触发 AI 凑字符串):
365
2281
 
366
2282
  ```
367
2283
  3. **按业务目标选择 `createAndJoinRoom()` 或 `joinRoom()`** — 房主快速创建并入会、
368
- 以及无法确认房间是否存在时,都更适合 `createAndJoinRoom()`;只有已知房间已存在
2284
+ 以及无法确认房间是否存在时,都更适合 `createAndJoinRoom()`;只有已知房间已存在
2285
+ 以及无法确认房间是否存在时,都更适合 `createAndJoinRoom()`;只有已知房间已存在
369
2286
  时才直接使用 `joinRoom()`。
370
2287
  **Verify**: 检查是否把"房主创建并入会""已知房间存在直接加入""存在性未知时尝试
371
2288
  进入"这三类路径明确区分。
372
2289
 
373
- 5. **为密码房和常见入会错误预留业务反馈** — 无 UI 接入时,密码输入、重试和错误
2290
+ 5. **为密码房和常见入会错误预留业务反馈** — 无 UI 接入时,密码输入、重试和错误
2291
+ 5. **为密码房和常见入会错误预留业务反馈** — 无 UI 接入时,密码输入、重试和错误
374
2292
  提示都需要页面自行承接。
375
2293
  **Verify**: 检查加入流程是否处理 `ERR_NEED_PASSWORD`、`ERR_WRONG_PASSWORD`
376
2294
  或等价失败提示。
377
2295
  ```
378
2296
 
379
- 红旗词诊断:「按业务」「或」「等价」全部命中。规则文字承诺的语义远超 backtick 能验的范围。
2297
+ 红旗词诊断:「按业务」「或」「等价」全部命中。规则文字承诺的语义远超 backtick 能验的范围。
2298
+ 红旗词诊断:「按业务」「或」「等价」全部命中。规则文字承诺的语义远超 backtick 能验的范围。
380
2299
 
381
- **改后**:
2300
+ **改后**:
2301
+ ✅ **改后**:
382
2302
 
383
- 「代码生成约束」→ MUST
2303
+ 「代码生成约束」→ MUST:
2304
+ 「代码生成约束」→ MUST:
384
2305
  ```
385
- 3. **必须调用房间进入 API(`createAndJoinRoom` 或 `joinRoom` 至少其一)** — 否则
2306
+ 3. **必须调用房间进入 API(`createAndJoinRoom` 或 `joinRoom` 至少其一)** — 否则
2307
+ 3. **必须调用房间进入 API(`createAndJoinRoom` 或 `joinRoom` 至少其一)** — 否则
386
2308
  无法进房。
387
2309
  **Verify**: 检查 `createAndJoinRoom` 与 `joinRoom` 至少其一出现 ≥1 次。
388
2310
  ```
389
2311
 
390
- 「代码示例」→ 增加场景一/二/三,每个场景写完整可 copy 的代码。
2312
+ 「代码示例」→ 增加场景一/二/三,每个场景写完整可 copy 的代码。
2313
+ 「代码示例」→ 增加场景一/二/三,每个场景写完整可 copy 的代码。
391
2314
 
392
- 「最佳实践」→ 新增软规则段(apply 不验,AI 阅读):
2315
+ 「最佳实践」→ 新增软规则段(apply 不验,AI 阅读):
2316
+ 「最佳实践」→ 新增软规则段(apply 不验,AI 阅读):
393
2317
  ```
394
- - 房主快速创建会议 → 用 createAndJoinRoom(参考场景一)
395
- - 已知房间已存在 → 用 joinRoom(参考场景二)
396
- - 不确定房间是否存在 → 用 createAndJoinRoom(参考场景三)
2318
+ - 房主快速创建会议 → 用 createAndJoinRoom(参考场景一)
2319
+ - 已知房间已存在 → 用 joinRoom(参考场景二)
2320
+ - 不确定房间是否存在 → 用 createAndJoinRoom(参考场景三)
2321
+ - 房主快速创建会议 → 用 createAndJoinRoom(参考场景一)
2322
+ - 已知房间已存在 → 用 joinRoom(参考场景二)
2323
+ - 不确定房间是否存在 → 用 createAndJoinRoom(参考场景三)
397
2324
  - 密码房 / 入会错误处理 → 见场景四与「常见错误与场景对照」表
398
2325
  ```
399
2326
 
400
- 效果:
2327
+ 效果:
2328
+ 效果:
401
2329
  - apply 不再误杀「AI 用 catch 通用错误处理」的正确代码
402
2330
  - AI 读到「最佳实践」能按业务选 API
403
2331
  - 业务路径选择即使错了也不会因 verify fail 把 AI 推去凑字符串
404
2332
 
2333
+ ---
2334
+
2335
+ ---
2336
+
405
2337
  ##### 验证矩阵 [必填]
406
2338
 
407
- section 是平台 slice 末尾的**统一验证出口**,汇总该 slice 所有可 verify 的项,按 4 层分级。AI 生成代码后或人工 review 时,自上而下跑一遍即可完成验收。
2339
+ ###### 1️⃣ 你必须写什么
2340
+ 平台 slice 末尾的**统一验证出口**,汇总所有可 verify 的项,按 4 层分级。
2341
+ AI 生成代码后或人工 review 时,自上而下跑一遍即可完成验收。
2342
+ ###### 1️⃣ 你必须写什么
2343
+ 平台 slice 末尾的**统一验证出口**,汇总所有可 verify 的项,按 4 层分级。
2344
+ AI 生成代码后或人工 review 时,自上而下跑一遍即可完成验收。
2345
+
2346
+ 这是 SuperPowers「验证门」机制在 slice 层的落地——**禁止在没有跑过验证矩阵的情况下声称完成**。
2347
+
2348
+ ###### 2️⃣ 写作模板
2349
+ 这是 SuperPowers「验证门」机制在 slice 层的落地——**禁止在没有跑过验证矩阵的情况下声称完成**。
2350
+
2351
+ ###### 2️⃣ 写作模板
2352
+ ```markdown
2353
+ ## 验证矩阵
2354
+
2355
+ | 层级 | 检查项 | 验证手段 | 预期结果 |
2356
+ |------|--------|----------|---------|
2357
+ | **1. 编译级** | {项} | {命令} | {预期} |
2358
+ | **1. 编译级** | {项} | {命令} | {预期} |
2359
+ | **2. 静态规则级** | {项} | {grep 命令} | {预期} |
2360
+ | **2. 静态规则级** | {项} | {grep 命令} | {预期} |
2361
+ | **3. 运行时级** | {项} | {操作 + 查日志} | {预期日志} |
2362
+ | **3. 运行时级** | {项} | {操作 + 查日志} | {预期日志} |
2363
+ | **4. 业务行为级** | {项} | {人工观察} | {预期现象} |
2364
+ | **4. 业务行为级** | {项} | {人工观察} | {预期现象} |
2365
+ ```
2366
+
2367
+ ###### 3️⃣ ✅ 正例(摘自 live/ios/coguest-apply)
2368
+ ```markdown
2369
+ ## 验证矩阵
2370
+
2371
+ | 层级 | 检查项 | 验证手段 | 预期结果 |
2372
+ |------|--------|----------|---------|
2373
+ | **1. 编译级** | 模块导入齐全 | `xcodebuild build -scheme Demo` | exit code 0 |
2374
+ | **1. 编译级** | iOS 最低版本 ≥ 13.0 | 查 `Podfile`/`project.pbxproj` | `IPHONEOS_DEPLOYMENT_TARGET = 13.0` |
2375
+ | **1. 编译级** | {项} | {命令} | {预期} |
2376
+ | **1. 编译级** | {项} | {命令} | {预期} |
2377
+ | **2. 静态规则级** | {项} | {grep 命令} | {预期} |
2378
+ | **2. 静态规则级** | {项} | {grep 命令} | {预期} |
2379
+ | **3. 运行时级** | {项} | {操作 + 查日志} | {预期日志} |
2380
+ | **3. 运行时级** | {项} | {操作 + 查日志} | {预期日志} |
2381
+ | **4. 业务行为级** | {项} | {人工观察} | {预期现象} |
2382
+ | **4. 业务行为级** | {项} | {人工观察} | {预期现象} |
2383
+ ```
408
2384
 
2385
+ ###### 3️⃣ ✅ 正例(摘自 live/ios/coguest-apply)
409
2386
  ```markdown
410
2387
  ## 验证矩阵
411
2388
 
412
2389
  | 层级 | 检查项 | 验证手段 | 预期结果 |
413
2390
  |------|--------|----------|---------|
414
- | **1. 编译级** | 模块导入齐全 | `xcodebuild build ...` / `./gradlew assembleDebug` / `tsc --noEmit` | exit code 0 |
415
- | **1. 编译级** | 最低版本达标 | 查项目 deployment target | {版本} |
2391
+ | **1. 编译级** | 模块导入齐全 | `xcodebuild build -scheme Demo` | exit code 0 |
2392
+ | **1. 编译级** | iOS 最低版本 ≥ 13.0 | `Podfile`/`project.pbxproj` | `IPHONEOS_DEPLOYMENT_TARGET = 13.0` |
416
2393
  | **2. 静态规则级** | 所有 sink 都 `[weak self]` | `grep -E "sink\\s*\\{\\s*\\[weak self\\]"` | 匹配数 == sink 总数 |
417
2394
  | **2. 静态规则级** | AnyCancellable 是实例属性 | `grep "var cancellables: Set<AnyCancellable>"` | 至少 1 处 |
418
- | **2. 静态规则级** | 每个 .failure 有 errorMessage | 代码审查 + grep | 无裸 print |
419
- | **3. 运行时级** | 申请发送成功 | 观众点申请 → 查日志 | `[CoGuest] 申请已发送...` |
2395
+ | **2. 静态规则级** | 每个 .failure 有 errorMessage | `grep -B 5 "case .failure" \| grep errorMessage` | 无裸 print |
2396
+ | **3. 运行时级** | 申请发送成功 | 观众点申请 → 查日志 | `[CoGuest] 申请已发送` |
2397
+ | **2. 静态规则级** | 每个 .failure 有 errorMessage | `grep -B 5 "case .failure" \| grep errorMessage` | 无裸 print |
2398
+ | **3. 运行时级** | 申请发送成功 | 观众点申请 → 查日志 | `[CoGuest] 申请已发送` |
420
2399
  | **3. 运行时级** | 主播收到事件 | 主播端查日志 | `onGuestApplicationReceived` |
421
- | **3. 运行时级** | 超时 UI 反馈 | 主播不响应,等 30s | UI 展示"申请超时" |
2400
+ | **3. 运行时级** | 超时 UI 反馈 | 主播不响应,等 30s | UI 展示"申请超时" |
2401
+ | **3. 运行时级** | 超时 UI 反馈 | 主播不响应,等 30s | UI 展示"申请超时" |
422
2402
  | **4. 业务行为级** | 通过前设备未开 | 点申请但未同意 | 摄像头指示灯不亮 |
423
2403
  | **4. 业务行为级** | 断开后设备关闭 | 连麦中主动断开 | 摄像头指示灯熄灭 |
424
2404
  ```
425
2405
 
426
- **4 个层级说明**:
2406
+ ###### 4️⃣ 4 个层级说明
2407
+ ###### 4️⃣ 4 个层级说明
427
2408
 
428
2409
  | 层级 | 含义 | 谁来跑 |
429
2410
  |------|------|--------|
430
2411
  | 1. **编译级** | 代码能编译通过、依赖齐全 | CI / AI 自动 |
431
- | 2. **静态规则级** | 不跑代码,纯静态扫描/ grep 就能查的规则 | CI / AI 自动 |
2412
+ | 2. **静态规则级** | 不跑代码,纯静态扫描/grep 就能查的规则 | CI / AI 自动 |
2413
+ | 2. **静态规则级** | 不跑代码,纯静态扫描/grep 就能查的规则 | CI / AI 自动 |
432
2414
  | 3. **运行时级** | 跑起来后通过日志锚点可观察的行为 | AI 半自动 / 人工 |
433
2415
  | 4. **业务行为级** | 需要人眼看 UI / 硬件状态的业务语义 | 人工 |
434
2416
 
435
- > **与 MUST 规则的对应关系**:
2417
+ > **与 MUST 规则的对应关系**:
2418
+ > **与 MUST 规则的对应关系**:
436
2419
  >
437
- > - 「层级 1 编译级」与「层级 2 静态规则级」是 apply 的**硬约束区域**——这两层的检查项基本对应「代码生成约束」里的 MUST / MUST NOTapply 自动跑、命中失败会 fail
438
- > - 「层级 3 运行时级」与「层级 4 业务行为级」是**软规则区域**——属于运行时观察 / 业务语义校验,apply 不验,需要 AI 半自动或人工跑。这些层级的内容对应「MUST 规则维度对齐原则」里的「软规则」(业务选择、调用顺序、架构边界等机械验证不了的项目)。
439
-
440
- **要求**:
441
- - 每条「代码生成约束」的 MUST/MUST NOT 都应在矩阵中有对应行(层级 1 2)
442
- - 至少 1 条层级 3 的检查,证明代码真的能跑起来
443
- - 至少 1 条层级 4 的检查,证明业务语义正确(通常是「ALWAYS/NEVER」的运行时体现)
2420
+ > - 「层级 1 编译级」与「层级 2 静态规则级」是 apply 的**硬约束区域**——基本对应「代码生成约束」里的 MUST/MUST NOT,apply 自动跑、命中失败会 fail
2421
+ > - 「层级 3 运行时级」与「层级 4 业务行为级」是**软规则区域**——属于运行时观察 / 业务语义校验,apply 不验,需要 AI 半自动或人工跑
2422
+
2423
+ ###### 5️⃣ 必填项语义三件套
2424
+ - **违反后果**:验证矩阵不全 AI/人工无法系统性自验 "应该没问题"上线 线上事故
2425
+ - **验证手段**:
2426
+ ```bash
2427
+ python scripts/check_verify_matrix.py {file}
2428
+ # 通过标准:
2429
+ # - 4 个层级各 ≥1 行
2430
+ # - 每条「代码生成约束」MUST/MUST NOT 都能在矩阵层级 1 或 2 找到对应行
2431
+ # - 至少 1 条层级 3、1 条层级 4
2432
+ ```
2433
+ - **绕过条件**:无
2434
+ > - 「层级 1 编译级」与「层级 2 静态规则级」是 apply 的**硬约束区域**——基本对应「代码生成约束」里的 MUST/MUST NOT,apply 自动跑、命中失败会 fail
2435
+ > - 「层级 3 运行时级」与「层级 4 业务行为级」是**软规则区域**——属于运行时观察 / 业务语义校验,apply 不验,需要 AI 半自动或人工跑
2436
+
2437
+ ###### 5️⃣ 必填项语义三件套
2438
+ - **违反后果**:验证矩阵不全 → AI/人工无法系统性自验 → "应该没问题"上线 → 线上事故
2439
+ - **验证手段**:
2440
+ ```bash
2441
+ python scripts/check_verify_matrix.py {file}
2442
+ # 通过标准:
2443
+ # - 4 个层级各 ≥1 行
2444
+ # - 每条「代码生成约束」MUST/MUST NOT 都能在矩阵层级 1 或 2 找到对应行
2445
+ # - 至少 1 条层级 3、1 条层级 4
2446
+ ```
2447
+ - **绕过条件**:无
444
2448
 
445
2449
  ---
446
2450
 
447
- ## 五、完成自查清单(DoD
2451
+ ## 五、完成自查清单(DoD)
2452
+ ## 五、完成自查清单(DoD)
448
2453
 
449
- 研发写完 slice 后,对照清单逐条打勾。任何一项未满足 = 未完成。
2454
+ 研发写完 slice 后,对照清单逐条打勾。**任何一项未满足 = 未完成,不允许提 PR**。
2455
+
2456
+ > ⚠️ 仅打勾不跑命令 = 视为未验证。每条标了"验证命令"的项,必须在 PR 描述粘贴命令输出。
2457
+ 研发写完 slice 后,对照清单逐条打勾。**任何一项未满足 = 未完成,不允许提 PR**。
2458
+
2459
+ > ⚠️ 仅打勾不跑命令 = 视为未验证。每条标了"验证命令"的项,必须在 PR 描述粘贴命令输出。
450
2460
 
451
2461
  ### 产品级概览 DoD
452
2462
 
453
- - [ ] Frontmatter 必填字段齐全(id / name / product / tags≥3 / platforms
2463
+ - [ ] Frontmatter 必填字段齐全(id / name / product / tags≥3 / platforms)
2464
+ 验证:`python scripts/validate_frontmatter.py {file}` 退出码 0
2465
+ - [ ] Frontmatter 必填字段齐全(id / name / product / tags≥3 / platforms)
2466
+ 验证:`python scripts/validate_frontmatter.py {file}` 退出码 0
454
2467
  - [ ] 每个 section 标题都带 `[必填]` / `[可选]` / `[条件必填]` 标签
455
2468
  - [ ] `功能说明` 能让一个没接触过 TRTC 的开发者 30 秒内明白这个能力是什么
456
2469
  - [ ] `核心概念` 无平台特有 API 签名(自查:逐个 API 名过一遍,iOS/Android 开发者读到都不应困惑)
457
2470
  - [ ] `最佳实践` 的每条 ALWAYS/NEVER 都是**行为级**("做什么"),不含代码结构细节("怎么写")
458
2471
  - [ ] `排障指南` 至少包含 1 张错误码表 + 1 棵排障流程树
459
- - [ ] `关联知识` 的所有引用 slice ID `index.yaml` 中存在(或标注 `status: planned`)
2472
+ - [ ] `关联知识` 的所有引用 slice ID 在对应的 per-product platform index 中存在(或标注 `status: planned`)
460
2473
  - [ ] 全文不包含具体平台的类名/方法名/关键字(如 `ViewController`、`[weak self]`、`PassthroughSubject`)
461
2474
 
462
2475
  ### 平台实现文件 DoD
463
2476
 
464
- - [ ] Frontmatter 必填字段齐全(id / platform / api_docs≥1
465
- - [ ] `api_docs` 链接精确到**类/模块**级,不是 SDK 首页或教程页
2477
+ - [ ] Frontmatter 必填字段齐全(id / platform / api_docs≥1)
2478
+ - [ ] `api_docs` 链接精确到**类/模块**级
2479
+ 验证:`python scripts/validate_api_docs.py {file}` 全部 200 + 含 `/documentation/` 或 `/api/`
2480
+ - [ ] Frontmatter 必填字段齐全(id / platform / api_docs≥1)
2481
+ - [ ] `api_docs` 链接精确到**类/模块**级
2482
+ 验证:`python scripts/validate_api_docs.py {file}` 全部 200 + 含 `/documentation/` 或 `/api/`
466
2483
  - [ ] 每个 section 标题都带必填/可选标签
467
- - [ ] `前置条件` 没有重复 base-setup / login-auth 已覆盖的通用依赖
468
- - [ ] `代码示例` 满足**代码示例标准**的 6 条最低要求(见第四节表格)
469
- - [ ] 每个 `.failure` / `catch` / `error` 分支都有面向用户的可见处理,不允许只 `print`
470
- - [ ] 每段代码都有日志锚点,供「验证矩阵」层级 3 使用
471
- - [ ] `调用时序`:若涉及多角色异步交互或回调嵌套 ≥3 层,必须画;否则可省
472
- - [ ] `平台特有注意事项` 至少 1 条,且每条都是「该平台独有 + 不写出来研发会踩坑」
473
- - [ ] `代码生成约束` 的每条 MUST / MUST NOT 都使用 **prose + backtick** 格式:`**Verify**: 检查是否存在 \`symbol\``,每条规则的 backtick 符号是 apply 唯一 grep 的目标
474
- - [ ] 每条 MUST / MUST NOT 通过「自查三问」(见第四节「MUST 规则的维度对齐原则」)
475
- - [ ] 每条 MUST / MUST NOT 不含「红旗词」(或 / 任一 / 等价 / 按业务 / 根据场景 / 留给 / 负责);含红旗词的规则要么拆成原子规则,要么下沉到软规则区
476
- - [ ] `代码生成约束` MUST / MUST NOT 与产品级 ALWAYS / NEVER 不重复(前者管代码结构,后者管运行时行为)
477
- - [ ] `验证矩阵` 的 4 个层级都有至少 1 行
478
- - [ ] `验证矩阵` 覆盖了所有 MUST / MUST NOT 规则(每条规则都能在矩阵中找到对应行)
479
-
480
- ### Slice 整体 DoD(提交合并前)
2484
+ - [ ] `前置条件` 不重复 base-setup / login-auth 内容
2485
+ 验证:`grep -E "pod install|npm install|implementation" {file}` 命中 0 次
2486
+ - [ ] `代码示例` 满足 6 条最低标准
2487
+ 验证:抽取代码块编译通过 + `grep -E "\\.\\.\\."` 命中 0
2488
+ - [ ] 每个 `.failure` / `catch` / `error` 分支都有 UI 可见的处理
2489
+ 验证:`grep -E "errorMessage|alert|toast"` 在每个 failure 块至少 1
2490
+ - [ ] 每段代码有日志锚点(带模块前缀)
2491
+ - [ ] `调用时序`:触发条件命中则必有
2492
+ - [ ] `平台特有注意事项` 1 条,每条含"必须做:"
2493
+ - [ ] `代码生成约束` MUST 3 条,MUST NOT 2 条,每条有 backtick + Verify
2494
+ 验证:`python scripts/check_must_rules.py {file}` 通过
2495
+ - [ ] 每条 MUST/MUST NOT 通过「自查三问」
2496
+ - [ ] 每条 MUST/MUST NOT 不含红旗词
2497
+ 验证:`grep -E "或|任一|等价|按业务|根据场景|留给|负责" {file}` 在 MUST 段落命中 0 次
2498
+ - [ ] `代码生成约束` 与产品级 ALWAYS/NEVER 不重复(前者管代码结构,后者管运行时行为)
2499
+ - [ ] `验证矩阵` 4 个层级各 ≥ 1 行,覆盖所有 MUST/MUST NOT
2500
+ 验证:`python scripts/check_verify_matrix.py {file}` 通过
2501
+ - [ ] `前置条件` 不重复 base-setup / login-auth 内容
2502
+ 验证:`grep -E "pod install|npm install|implementation" {file}` 命中 0 次
2503
+ - [ ] `代码示例` 满足 6 条最低标准
2504
+ 验证:抽取代码块编译通过 + `grep -E "\\.\\.\\."` 命中 0 次
2505
+ - [ ] 每个 `.failure` / `catch` / `error` 分支都有 UI 可见的处理
2506
+ 验证:`grep -E "errorMessage|alert|toast"` 在每个 failure 块至少 1 处
2507
+ - [ ] 每段代码有日志锚点(带模块前缀)
2508
+ - [ ] `调用时序`:触发条件命中则必有
2509
+ - [ ] `平台特有注意事项` ≥ 1 条,每条含"必须做:"
2510
+ - [ ] `代码生成约束` MUST ≥ 3 条,MUST NOT ≥ 2 条,每条有 backtick + Verify
2511
+ 验证:`python scripts/check_must_rules.py {file}` 通过
2512
+ - [ ] 每条 MUST/MUST NOT 通过「自查三问」
2513
+ - [ ] 每条 MUST/MUST NOT 不含红旗词
2514
+ 验证:`grep -E "或|任一|等价|按业务|根据场景|留给|负责" {file}` 在 MUST 段落命中 0 次
2515
+ - [ ] `代码生成约束` 与产品级 ALWAYS/NEVER 不重复(前者管代码结构,后者管运行时行为)
2516
+ - [ ] `验证矩阵` 4 个层级各 ≥ 1 行,覆盖所有 MUST/MUST NOT
2517
+ 验证:`python scripts/check_verify_matrix.py {file}` 通过
2518
+
2519
+ ### Slice 整体 DoD(提交合并前)
2520
+ ### Slice 整体 DoD(提交合并前)
481
2521
 
482
2522
  - [ ] 通过第二节的 4 个拆分问题自查(特别是**问题 4:能被 ≥2 个场景复用**)
483
- - [ ] `index.yaml` 中登记,`status` 标记为 `active` 或 `planned`
2523
+ - [ ] 在对应的 per-product platform index 中登记,`status` 标记为 `active` 或 `planned`
484
2524
  - [ ] 如果是反馈 slice(🅱️),在描述中说明其对应的用户高频问题来源
485
2525
 
486
2526
  ---
@@ -489,58 +2529,96 @@ api_docs: # [必填] 该平台 API 参考文档链接(至少
489
2529
 
490
2530
  ### 6.1 Slice 之间的引用规范
491
2531
 
492
- 目的:避免重复写、避免知识孤岛、让 AI 能沿着引用链找到完整上下文。
2532
+ 目的:避免重复写、避免知识孤岛、让 AI 沿引用链找到完整上下文。
2533
+ 目的:避免重复写、避免知识孤岛、让 AI 沿引用链找到完整上下文。
493
2534
 
494
2535
  #### 何时必须引用、不允许重复
495
2536
 
496
- 以下内容已由专门 slice 承载,其他 slice **必须引用、不允许重复**:
497
-
498
2537
  | 内容 | 承载 slice |
499
2538
  |------|-----------|
500
2539
  | SDK 安装、主包依赖、基础权限声明 | `{product}/login-auth` 或 `{product}/base-setup` |
501
2540
  | 登录认证流程 | `{product}/login-auth` |
502
2541
  | 跨 slice 复用的错误码总表 | `{product}/error-codes` |
503
- | 设备开关(摄像头/麦克风) | `{product}/device-control` |
2542
+ | 设备开关(摄像头/麦克风) | `{product}/device-control` |
2543
+ | 设备开关(摄像头/麦克风) | `{product}/device-control` |
504
2544
 
505
- 引用写法统一:
2545
+ 引用写法统一:
2546
+ 引用写法统一:
506
2547
  ```markdown
507
- 见 [login-auth 平台 slice](../login-auth.md)SDK 安装、Info.plist 权限)
508
- 前置依赖:`LoginStore.shared.isLogin == true`(→ live/login-auth
2548
+ 见 [login-auth 平台 slice](../login-auth.md)(SDK 安装、Info.plist 权限)
2549
+ 前置依赖:`LoginStore.shared.isLogin == true`(→ live/login-auth)
2550
+ 见 [login-auth 平台 slice](../login-auth.md)(SDK 安装、Info.plist 权限)
2551
+ → 前置依赖:`LoginStore.shared.isLogin == true`(→ live/login-auth)
509
2552
  ```
510
2553
 
511
2554
  #### 何时允许适度重复
512
2555
 
513
- 仅以下两种情况允许少量重复:
2556
+ 仅以下两种情况:
2557
+ 仅以下两种情况:
514
2558
 
515
- 1. **单行关键代码** — 如果不复述一行代码会让阅读体验跳跃(比如 `import Combine`),可以保留这一行并备注"详见 xxx slice"
516
- 2. **错误码的本地化提示文案** — 可以在各自 slice 中重复出现,因为每个 slice 的错误码含义上下文不同
2559
+ 1. **单行关键代码** — 不复述会让阅读跳跃(如 `import Combine`),保留一行并备注"详见 xxx slice"
2560
+ 2. **错误码的本地化提示文案** — slice 上下文不同,可重复
2561
+ 1. **单行关键代码** — 不复述会让阅读跳跃(如 `import Combine`),保留一行并备注"详见 xxx slice"
2562
+ 2. **错误码的本地化提示文案** — 各 slice 上下文不同,可重复
517
2563
 
518
2564
  #### 引用格式统一
519
2565
 
520
2566
  | 场景 | 统一写法 |
521
2567
  |------|---------|
522
- | 正文引用其他 slice | `[slice-id](相对路径.md)` 或 `(→ slice-id)` |
523
- | 代码注释中标注依赖 | `// 前置:xxx 完成(→ slice-id)` |
524
- | Frontmatter 中的 related | 只写 `slice-id`,不带路径 |
525
- | 指向官方文档 | 放在平台文件的 `api_docs` 中,正文不重复 URL |
2568
+ | 正文引用其他 slice | `[slice-id](相对路径.md)` 或 `(→ slice-id)` |
2569
+ | 代码注释中标注依赖 | `// 前置:xxx 完成(→ slice-id)` |
2570
+ | Frontmatter 中的 related | 只写 `slice-id`,不带路径 |
2571
+ | 指向官方文档 | 放在平台文件 `api_docs`,正文不重复 URL |
2572
+ | 正文引用其他 slice | `[slice-id](相对路径.md)` 或 `(→ slice-id)` |
2573
+ | 代码注释中标注依赖 | `// 前置:xxx 完成(→ slice-id)` |
2574
+ | Frontmatter 中的 related | 只写 `slice-id`,不带路径 |
2575
+ | 指向官方文档 | 放在平台文件 `api_docs`,正文不重复 URL |
526
2576
 
527
2577
  ### 6.2 Slice 与 Scenario 的边界
528
2578
 
529
- Slice 和 Scenario 经常会让人纠结某段内容该放哪,给一个简单判定:
530
-
531
2579
  | 内容类型 | 归属 | 理由 |
532
2580
  |---------|------|------|
533
- | 单一能力的完整实现(含所有角色、所有失败分支) | **Slice** | slice 是零件,必须自洽 |
534
- | 同一能力内部的多步骤先后顺序(如:申请→等待→开设备) | **Slice** | 属于该能力内部时序 |
535
- | 多个能力之间的组装顺序(如:登录→进房→推流→连麦) | **Scenario** | scenario 才知道全局顺序 |
536
- | 业务选型决策(如:选择 1v1 通话还是多人连麦) | **Scenario** | slice 不关心业务形态 |
537
- | 跨能力的状态共享(如:登录 Store 在哪个层级持有) | **Scenario** | slice 内部只声明依赖,不决定生命周期宿主 |
2581
+ | 单一能力的完整实现(含所有角色、所有失败分支) | **Slice** | slice 是零件,必须自洽 |
2582
+ | 同一能力内部的多步骤先后顺序(申请→等待→开设备) | **Slice** | 属于该能力内部时序 |
2583
+ | 多个能力之间的组装顺序(登录→进房→推流→连麦) | **Scenario** | scenario 才知道全局顺序 |
2584
+ | 业务选型决策(选 1v1 通话还是多人连麦) | **Scenario** | slice 不关心业务形态 |
2585
+ | 跨能力的状态共享(登录 Store 在哪个层级持有) | **Scenario** | slice 内部只声明依赖 |
2586
+ | 单一能力的完整实现(含所有角色、所有失败分支) | **Slice** | slice 是零件,必须自洽 |
2587
+ | 同一能力内部的多步骤先后顺序(申请→等待→开设备) | **Slice** | 属于该能力内部时序 |
2588
+ | 多个能力之间的组装顺序(登录→进房→推流→连麦) | **Scenario** | scenario 才知道全局顺序 |
2589
+ | 业务选型决策(选 1v1 通话还是多人连麦) | **Scenario** | slice 不关心业务形态 |
2590
+ | 跨能力的状态共享(登录 Store 在哪个层级持有) | **Scenario** | slice 内部只声明依赖 |
538
2591
  | 某个能力特有的 UI 定制点 | **Slice** | UI 定制依附于能力 |
539
2592
  | 场景级的 UI 布局/导航流程 | **Scenario** | 属于场景形态 |
540
2593
 
541
- **反例自查**:
542
- - ❌ 一个 slice 的代码示例里写了「先调用登录、再调用本能力」 → 登录的组装应该交给 scenarioslice 只声明 `// 前置:登录完成(→ xxx)`
543
- - ❌ 一个 scenario 里大段贴某个能力的完整失败处理代码 → 应该是 scenario 引用 slice,而不是抄写 slice
2594
+ **反例自查**:
2595
+ - ❌ 一个 slice 的代码示例里写了「先调用登录、再调用本能力」 → 登录的组装应该交给 scenario,slice 只声明 `// 前置:登录完成(→ xxx)`
2596
+ - ❌ 一个 scenario 里大段贴某个能力的完整失败处理代码 → 应该是 scenario 引用 slice,而不是抄写 slice
2597
+ **反例自查**:
2598
+ - ❌ 一个 slice 的代码示例里写了「先调用登录、再调用本能力」 → 登录的组装应该交给 scenario,slice 只声明 `// 前置:登录完成(→ xxx)`
2599
+ - ❌ 一个 scenario 里大段贴某个能力的完整失败处理代码 → 应该是 scenario 引用 slice,而不是抄写 slice
544
2600
 
545
2601
  ---
546
2602
 
2603
+ ## 附录:验证脚本清单
2604
+
2605
+ 本 spec 引用的所有 `python scripts/xxx.py` 必须真实存在,否则三件套是空头支票。脚本位于 `scripts/` 目录:
2606
+
2607
+ | 脚本 | 作用 |
2608
+ |------|------|
2609
+ | `validate_frontmatter.py` | 检查 frontmatter 字段齐全 + 与 index.yaml 一致 |
2610
+ | `validate_api_docs.py` | 检查 api_docs 链接可访问 + 路径含 `/documentation/` 或 `/api/` |
2611
+ | `check_must_rules.py` | 红旗词扫描 + 每条 MUST 都有 Verify + Verify 内有 backtick |
2612
+ | `check_verify_matrix.py` | 验证矩阵 4 层各 ≥1 + 覆盖所有 MUST |
2613
+ | `extract_code.py` | 抽取 markdown 中的代码块,供编译验证 |
2614
+ ## 附录:验证脚本清单
2615
+
2616
+ 本 spec 引用的所有 `python scripts/xxx.py` 必须真实存在,否则三件套是空头支票。脚本位于 `scripts/` 目录:
2617
+
2618
+ | 脚本 | 作用 |
2619
+ |------|------|
2620
+ | `validate_frontmatter.py` | 检查 frontmatter 字段齐全 + 与 index.yaml 一致 |
2621
+ | `validate_api_docs.py` | 检查 api_docs 链接可访问 + 路径含 `/documentation/` 或 `/api/` |
2622
+ | `check_must_rules.py` | 红旗词扫描 + 每条 MUST 都有 Verify + Verify 内有 backtick |
2623
+ | `check_verify_matrix.py` | 验证矩阵 4 层各 ≥1 + 覆盖所有 MUST |
2624
+ | `extract_code.py` | 抽取 markdown 中的代码块,供编译验证 |