opencode-skills-collection 4.0.69 → 4.0.70

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 (185) hide show
  1. package/bundled-skills/.antigravity-install-manifest.json +39 -1
  2. package/bundled-skills/api-integration-architect/SKILL.md +241 -0
  3. package/bundled-skills/apify-generate-output-schema/SKILL.md +438 -0
  4. package/bundled-skills/apify-integration-development/SKILL.md +168 -0
  5. package/bundled-skills/apify-integration-development/references/ai-framework-package.md +158 -0
  6. package/bundled-skills/apify-integration-development/references/ai-harness-plugin.md +192 -0
  7. package/bundled-skills/apify-integration-development/references/sdk-integration.md +236 -0
  8. package/bundled-skills/apify-integration-development/references/workflow-automation.md +163 -0
  9. package/bundled-skills/architecture-review/README.md +42 -0
  10. package/bundled-skills/architecture-review/SKILL.md +77 -0
  11. package/bundled-skills/architecture-review/examples.md +11 -0
  12. package/bundled-skills/architecture-review/reference/best-practices.md +7 -0
  13. package/bundled-skills/architecture-review/reference/capabilities.md +20 -0
  14. package/bundled-skills/architecture-review/reference/fallbacks.md +11 -0
  15. package/bundled-skills/architecture-review/reference/graph.md +15 -0
  16. package/bundled-skills/architecture-review/reference/mcp.md +14 -0
  17. package/bundled-skills/architecture-review/reference/workflow.md +15 -0
  18. package/bundled-skills/architecture-review/templates/architecture-review.md +21 -0
  19. package/bundled-skills/code-review-sensei/SKILL.md +177 -0
  20. package/bundled-skills/codebase-onboarding/README.md +42 -0
  21. package/bundled-skills/codebase-onboarding/SKILL.md +77 -0
  22. package/bundled-skills/codebase-onboarding/examples.md +11 -0
  23. package/bundled-skills/codebase-onboarding/reference/best-practices.md +7 -0
  24. package/bundled-skills/codebase-onboarding/reference/capabilities.md +20 -0
  25. package/bundled-skills/codebase-onboarding/reference/fallbacks.md +11 -0
  26. package/bundled-skills/codebase-onboarding/reference/graph.md +15 -0
  27. package/bundled-skills/codebase-onboarding/reference/mcp.md +14 -0
  28. package/bundled-skills/codebase-onboarding/reference/workflow.md +15 -0
  29. package/bundled-skills/codebase-onboarding/templates/repository-onboarding.md +21 -0
  30. package/bundled-skills/connection-auth-rules/SKILL.md +199 -0
  31. package/bundled-skills/connection-auth-rules/fetch_schema.py +320 -0
  32. package/bundled-skills/dependency-analysis/README.md +42 -0
  33. package/bundled-skills/dependency-analysis/SKILL.md +76 -0
  34. package/bundled-skills/dependency-analysis/examples.md +11 -0
  35. package/bundled-skills/dependency-analysis/reference/best-practices.md +7 -0
  36. package/bundled-skills/dependency-analysis/reference/capabilities.md +20 -0
  37. package/bundled-skills/dependency-analysis/reference/fallbacks.md +11 -0
  38. package/bundled-skills/dependency-analysis/reference/graph.md +15 -0
  39. package/bundled-skills/dependency-analysis/reference/mcp.md +14 -0
  40. package/bundled-skills/dependency-analysis/reference/workflow.md +15 -0
  41. package/bundled-skills/dependency-analysis/templates/dependency-review.md +21 -0
  42. package/bundled-skills/devops-pipeline-builder/SKILL.md +200 -0
  43. package/bundled-skills/eas-app-stores/SKILL.md +197 -0
  44. package/bundled-skills/eas-app-stores/agents/openai.yaml +4 -0
  45. package/bundled-skills/eas-app-stores/references/app-store-metadata.md +497 -0
  46. package/bundled-skills/eas-app-stores/references/ios-app-store.md +376 -0
  47. package/bundled-skills/eas-app-stores/references/native-ios.md +167 -0
  48. package/bundled-skills/eas-app-stores/references/play-store.md +244 -0
  49. package/bundled-skills/eas-app-stores/references/testflight.md +62 -0
  50. package/bundled-skills/eas-app-stores/references/workflows.md +120 -0
  51. package/bundled-skills/eas-hosting/SKILL.md +448 -0
  52. package/bundled-skills/eas-hosting/agents/openai.yaml +4 -0
  53. package/bundled-skills/eas-observe/SKILL.md +75 -0
  54. package/bundled-skills/eas-observe/agents/openai.yaml +4 -0
  55. package/bundled-skills/eas-observe/references/metrics.md +98 -0
  56. package/bundled-skills/eas-observe/references/queries.md +403 -0
  57. package/bundled-skills/eas-observe/references/setup.md +476 -0
  58. package/bundled-skills/eas-observe/references/third-party.md +136 -0
  59. package/bundled-skills/eas-simulator/SKILL.md +251 -0
  60. package/bundled-skills/eas-simulator/agents/openai.yaml +4 -0
  61. package/bundled-skills/eas-simulator/references/controllers.md +135 -0
  62. package/bundled-skills/eas-simulator/references/run-your-app.md +240 -0
  63. package/bundled-skills/eas-simulator/references/troubleshooting.md +47 -0
  64. package/bundled-skills/eas-workflows/SKILL.md +119 -0
  65. package/bundled-skills/eas-workflows/agents/openai.yaml +4 -0
  66. package/bundled-skills/eas-workflows/scripts/fetch.js +109 -0
  67. package/bundled-skills/expo-animation/LICENSE +21 -0
  68. package/bundled-skills/expo-animation/RECIPES.md +385 -0
  69. package/bundled-skills/expo-animation/SKILL.md +295 -0
  70. package/bundled-skills/expo-animation/agents/openai.yaml +4 -0
  71. package/bundled-skills/fact-check-x-unified/SKILL.md +178 -0
  72. package/bundled-skills/fact-check-x-unified/agents/openai.yaml +4 -0
  73. package/bundled-skills/fact-check-x-unified/references/acceptance-criteria.md +44 -0
  74. package/bundled-skills/fact-check-x-unified/references/contracts.md +39 -0
  75. package/bundled-skills/fact-check-x-unified/scripts/common.py +31 -0
  76. package/bundled-skills/fact-check-x-unified/scripts/fact_check_x.py +1832 -0
  77. package/bundled-skills/fact-check-x-unified/scripts/trusted_search_config.py +324 -0
  78. package/bundled-skills/fact-check-x-unified/tests/anchor_downgrade_test.py +90 -0
  79. package/bundled-skills/fact-check-x-unified/tests/multi_platform_test.py +369 -0
  80. package/bundled-skills/fact-check-x-unified/tests/smoke_test.py +740 -0
  81. package/bundled-skills/fact-check-x-unified/tests/stage_checkpoint_test.py +103 -0
  82. package/bundled-skills/fact-check-x-unified/tests/trusted_search_config_test.py +156 -0
  83. package/bundled-skills/gpt-taste/SKILL.md +8 -1
  84. package/bundled-skills/hf-cli/SKILL.md +263 -0
  85. package/bundled-skills/huggingface-community-evals/SKILL.md +228 -0
  86. package/bundled-skills/huggingface-community-evals/examples/.env.example +3 -0
  87. package/bundled-skills/huggingface-community-evals/examples/USAGE_EXAMPLES.md +101 -0
  88. package/bundled-skills/huggingface-community-evals/scripts/inspect_eval_uv.py +104 -0
  89. package/bundled-skills/huggingface-community-evals/scripts/inspect_vllm_uv.py +306 -0
  90. package/bundled-skills/huggingface-community-evals/scripts/lighteval_vllm_uv.py +297 -0
  91. package/bundled-skills/huggingface-datasets/SKILL.md +130 -0
  92. package/bundled-skills/jev-social/SKILL.md +182 -0
  93. package/bundled-skills/longbridge-derivatives/SKILL.md +117 -0
  94. package/bundled-skills/longbridge-derivatives/references/option.md +36 -0
  95. package/bundled-skills/longbridge-derivatives/references/options-advanced.md +101 -0
  96. package/bundled-skills/longbridge-derivatives/references/options-pnl.md +74 -0
  97. package/bundled-skills/longbridge-derivatives/references/options-strategy.md +82 -0
  98. package/bundled-skills/longbridge-derivatives/references/options-volatility.md +70 -0
  99. package/bundled-skills/longbridge-derivatives/references/warrant.md +12 -0
  100. package/bundled-skills/longbridge-quant/SKILL.md +151 -0
  101. package/bundled-skills/longbridge-quant/references/correlation.md +51 -0
  102. package/bundled-skills/longbridge-quant/references/execution-model.md +68 -0
  103. package/bundled-skills/longbridge-quant/references/factor-research.md +95 -0
  104. package/bundled-skills/longbridge-quant/references/factor-screen.md +101 -0
  105. package/bundled-skills/longbridge-quant/references/hedging.md +136 -0
  106. package/bundled-skills/longbridge-quant/references/ml-strategy.md +77 -0
  107. package/bundled-skills/longbridge-quant/references/multifactor.md +68 -0
  108. package/bundled-skills/longbridge-quant/references/pairs-trading.md +61 -0
  109. package/bundled-skills/longbridge-quant/references/quant-cli.md +133 -0
  110. package/bundled-skills/longbridge-quant/references/quant-stats.md +150 -0
  111. package/bundled-skills/longbridge-quant/references/seasonality.md +50 -0
  112. package/bundled-skills/longbridge-quant/references/strategy-optimizer.md +68 -0
  113. package/bundled-skills/longbridge-quant/references/volatility-strategy.md +52 -0
  114. package/bundled-skills/longbridge-research/SKILL.md +187 -0
  115. package/bundled-skills/longbridge-research/references/company-profile.md +96 -0
  116. package/bundled-skills/longbridge-research/references/company-tearsheet.md +82 -0
  117. package/bundled-skills/longbridge-research/references/competitive-analysis.md +81 -0
  118. package/bundled-skills/longbridge-research/references/consensus.md +92 -0
  119. package/bundled-skills/longbridge-research/references/coverage-initiation.md +76 -0
  120. package/bundled-skills/longbridge-research/references/defi-yield.md +60 -0
  121. package/bundled-skills/longbridge-research/references/finance-calendar.md +165 -0
  122. package/bundled-skills/longbridge-research/references/financial-planning.md +77 -0
  123. package/bundled-skills/longbridge-research/references/forecast-eps.md +39 -0
  124. package/bundled-skills/longbridge-research/references/fund-holder.md +44 -0
  125. package/bundled-skills/longbridge-research/references/hkipo-analysis.md +101 -0
  126. package/bundled-skills/longbridge-research/references/industry-peers.md +46 -0
  127. package/bundled-skills/longbridge-research/references/industry-rank.md +62 -0
  128. package/bundled-skills/longbridge-research/references/insider-trades.md +48 -0
  129. package/bundled-skills/longbridge-research/references/institution-rating.md +62 -0
  130. package/bundled-skills/longbridge-research/references/investment-ideas.md +69 -0
  131. package/bundled-skills/longbridge-research/references/investment-proposal.md +95 -0
  132. package/bundled-skills/longbridge-research/references/investors.md +87 -0
  133. package/bundled-skills/longbridge-research/references/onchain.md +70 -0
  134. package/bundled-skills/longbridge-research/references/post-investment.md +76 -0
  135. package/bundled-skills/longbridge-research/references/shareholder.md +72 -0
  136. package/bundled-skills/longbridge-research/references/short-positions.md +50 -0
  137. package/bundled-skills/longbridge-research/references/short-trades.md +50 -0
  138. package/bundled-skills/longbridge-research/references/stock-research.md +61 -0
  139. package/bundled-skills/longbridge-research/references/thesis-tracker.md +64 -0
  140. package/bundled-skills/makepad-2-0-animation/SKILL.md +318 -0
  141. package/bundled-skills/makepad-2-0-animation/references/animator-reference.md +433 -0
  142. package/bundled-skills/makepad-2-0-dsl/SKILL.md +492 -0
  143. package/bundled-skills/makepad-2-0-dsl/references/dsl-syntax-reference.md +511 -0
  144. package/bundled-skills/makepad-2-0-dsl/references/extended-guide.md +56 -0
  145. package/bundled-skills/makepad-2-0-dsl/references/property-system.md +757 -0
  146. package/bundled-skills/makepad-2-0-events/SKILL.md +497 -0
  147. package/bundled-skills/makepad-2-0-events/references/event-patterns.md +802 -0
  148. package/bundled-skills/makepad-2-0-events/references/extended-guide.md +590 -0
  149. package/bundled-skills/makepad-2-0-layout/SKILL.md +499 -0
  150. package/bundled-skills/makepad-2-0-layout/references/extended-guide.md +243 -0
  151. package/bundled-skills/makepad-2-0-layout/references/layout-patterns.md +881 -0
  152. package/bundled-skills/makepad-2-0-widgets/SKILL.md +261 -0
  153. package/bundled-skills/makepad-2-0-widgets/references/widget-advanced.md +648 -0
  154. package/bundled-skills/makepad-2-0-widgets/references/widget-catalog.md +547 -0
  155. package/bundled-skills/meeting-distiller-pro/SKILL.md +120 -0
  156. package/bundled-skills/monte-carlo-analyze-root-cause/SKILL.md +12 -1
  157. package/bundled-skills/monte-carlo-asset-health/SKILL.md +12 -1
  158. package/bundled-skills/monte-carlo-context-detection/SKILL.md +170 -0
  159. package/bundled-skills/monte-carlo-context-detection/references/signal-definitions.md +46 -0
  160. package/bundled-skills/remotion-captions/SKILL.md +57 -0
  161. package/bundled-skills/remotion-captions/agents/openai.yaml +7 -0
  162. package/bundled-skills/remotion-captions/assets/remotion-icon.svg +4 -0
  163. package/bundled-skills/remotion-captions/display-captions.md +190 -0
  164. package/bundled-skills/remotion-captions/import-srt-captions.md +73 -0
  165. package/bundled-skills/remotion-captions/transcribe-captions.md +70 -0
  166. package/bundled-skills/remotion-create/SKILL.md +106 -0
  167. package/bundled-skills/remotion-create/agents/openai.yaml +7 -0
  168. package/bundled-skills/remotion-create/assets/remotion-icon.svg +4 -0
  169. package/bundled-skills/remotion-create/tailwind.md +11 -0
  170. package/bundled-skills/remotion-create/video-layout.md +9 -0
  171. package/bundled-skills/remotion-docs/SKILL.md +67 -0
  172. package/bundled-skills/remotion-docs/agents/openai.yaml +7 -0
  173. package/bundled-skills/remotion-docs/assets/remotion-icon.svg +4 -0
  174. package/bundled-skills/remotion-interactivity/SKILL.md +270 -0
  175. package/bundled-skills/remotion-interactivity/agents/openai.yaml +7 -0
  176. package/bundled-skills/remotion-interactivity/assets/remotion-icon.svg +4 -0
  177. package/bundled-skills/remotion-render/SKILL.md +48 -0
  178. package/bundled-skills/remotion-render/agents/openai.yaml +7 -0
  179. package/bundled-skills/remotion-render/assets/remotion-icon.svg +4 -0
  180. package/bundled-skills/remotion-render/transparent-videos.md +106 -0
  181. package/bundled-skills/saas-pricing-strategist/SKILL.md +169 -0
  182. package/bundled-skills/score-eval/SKILL.md +35 -0
  183. package/bundled-skills/writing-guidelines/SKILL.md +60 -0
  184. package/package.json +1 -1
  185. package/skills_index.json +980 -3
@@ -0,0 +1,369 @@
1
+ #!/usr/bin/env python3
2
+ from __future__ import annotations
3
+
4
+ import json
5
+ import os
6
+ import subprocess
7
+ import sys
8
+ import tempfile
9
+ from pathlib import Path
10
+
11
+
12
+ ROOT = Path(__file__).resolve().parents[1]
13
+ SKILLS = ROOT.parent
14
+ if (ROOT / "modules").exists():
15
+ SKILLS = ROOT / "modules"
16
+ COMPARE = SKILLS / "fact-check-x-knowledge-compare" / "tests" / "fixtures"
17
+ AUTHORITY = SKILLS / "fact-check-x-authoritative-verify" / "tests" / "fixtures"
18
+
19
+
20
+ def command(*arguments: str) -> list[str]:
21
+ return [sys.executable, str(ROOT / "scripts" / "fact_check_x.py"), *arguments]
22
+
23
+
24
+ def run(arguments: list[str], environment: dict[str, str] | None = None) -> dict:
25
+ process = subprocess.run(
26
+ arguments,
27
+ text=True,
28
+ capture_output=True,
29
+ check=False,
30
+ env=environment,
31
+ )
32
+ if process.returncode:
33
+ raise AssertionError(process.stdout or process.stderr)
34
+ payload = json.loads([line for line in process.stdout.splitlines() if line.strip()][-1])
35
+ checkpoint = payload.get("checkpoint") or {}
36
+ acknowledgement = checkpoint.get("acknowledgement") or {}
37
+ if checkpoint.get("status") == "awaiting_user" and acknowledgement:
38
+ acknowledged = subprocess.run(
39
+ [sys.executable, str(ROOT / "scripts" / "fact_check_x.py"),
40
+ "acknowledge-stage", "--run-dir", str(Path(checkpoint["path"]).parent),
41
+ "--stage", checkpoint["stage"], "--token", acknowledgement["token"],
42
+ "--decision", "continue"],
43
+ text=True, capture_output=True, check=False, env=environment,
44
+ )
45
+ if acknowledged.returncode:
46
+ raise AssertionError(acknowledged.stdout or acknowledged.stderr)
47
+ return payload
48
+
49
+
50
+ def run_failed(arguments: list[str]) -> dict:
51
+ process = subprocess.run(
52
+ arguments,
53
+ text=True,
54
+ capture_output=True,
55
+ check=False,
56
+ )
57
+ if process.returncode == 0:
58
+ raise AssertionError("命令应以非零状态拒绝无平台输入")
59
+ return json.loads([line for line in process.stdout.splitlines() if line.strip()][-1])
60
+
61
+
62
+ def write_json(path: Path, value: dict) -> None:
63
+ path.write_text(json.dumps(value, ensure_ascii=False), encoding="utf-8")
64
+
65
+
66
+ def complete_pipeline(
67
+ root: Path,
68
+ case_name: str,
69
+ results: dict,
70
+ analysis: dict,
71
+ assessment: dict,
72
+ ) -> Path:
73
+ run_dir = root / f"{case_name}-run"
74
+ results_path = root / f"{case_name}-results.json"
75
+ analysis_path = root / f"{case_name}-analysis.json"
76
+ write_json(results_path, results)
77
+ write_json(analysis_path, analysis)
78
+
79
+ prepared = run(
80
+ command(
81
+ "prepare-comparison",
82
+ "--results",
83
+ str(results_path),
84
+ "--run-dir",
85
+ str(run_dir),
86
+ )
87
+ )
88
+ assert len(prepared["platforms"]) == len(results["platforms"])
89
+ completed = run(
90
+ command(
91
+ "complete-comparison",
92
+ "--results",
93
+ str(results_path),
94
+ "--analysis",
95
+ str(analysis_path),
96
+ "--run-dir",
97
+ str(run_dir),
98
+ )
99
+ )
100
+ assert completed["stage"] == "comparison_completed"
101
+ assert completed["artifacts"]["comparisonAnalysis"] == str(
102
+ (run_dir / "comparison-analysis.json").resolve()
103
+ )
104
+ assert (run_dir / "comparison-analysis.json").is_file()
105
+
106
+ keyless = {
107
+ **os.environ,
108
+ "TRUSTED_SEARCH_KEY": "",
109
+ "FACT_CHECK_X_TRUSTED_SEARCH_KEY_FILE": str(
110
+ run_dir / "missing-trusted-search-key"
111
+ ),
112
+ }
113
+ run(command("prepare-authority", "--run-dir", str(run_dir)), keyless)
114
+ run(
115
+ command(
116
+ "search-authority",
117
+ "--run-dir",
118
+ str(run_dir),
119
+ "--max-workers",
120
+ "12",
121
+ ),
122
+ keyless,
123
+ )
124
+ assessments = run_dir / "authority" / "assessments"
125
+ assessments.mkdir(parents=True)
126
+ write_json(assessments / "K1.json", assessment)
127
+ run(command("finalize-authority", "--run-dir", str(run_dir)), keyless)
128
+ delivered = run(
129
+ command(
130
+ "deliver",
131
+ "--results",
132
+ str(results_path),
133
+ "--run-dir",
134
+ str(run_dir),
135
+ ),
136
+ keyless,
137
+ )
138
+ assert delivered["status"] == "completed"
139
+ pipeline = json.loads((run_dir / "pipeline.json").read_text(encoding="utf-8"))
140
+ assert pipeline["artifacts"]["comparisonAnalysis"] == str(
141
+ (run_dir / "comparison-analysis.json").resolve()
142
+ )
143
+ assert all(
144
+ (run_dir / name).is_file()
145
+ for name in (
146
+ "01-capture-report.html",
147
+ "02-comparison-report.html",
148
+ "03-authority-report.html",
149
+ "04-final-report.html",
150
+ "05-complete-report-package.zip",
151
+ )
152
+ )
153
+ comparison_deliverable = (run_dir / "02-comparison-report.html").read_text(
154
+ encoding="utf-8"
155
+ )
156
+ assert all(
157
+ f'href="{target}"' in comparison_deliverable
158
+ for target in (
159
+ "01-capture-report.html",
160
+ "03-authority-report.html",
161
+ "04-final-report.html",
162
+ )
163
+ )
164
+ return run_dir
165
+
166
+
167
+ def main() -> int:
168
+ with tempfile.TemporaryDirectory(prefix="fact-check-x-dynamic-platform-") as temp:
169
+ root = Path(temp)
170
+ results_fixture = json.loads(
171
+ (COMPARE / "results.json").read_text(encoding="utf-8")
172
+ )
173
+ analysis_fixture = json.loads(
174
+ (COMPARE / "comparison-analysis.json").read_text(encoding="utf-8")
175
+ )
176
+ assessment_fixture = json.loads(
177
+ (AUTHORITY / "K1-assessment.json").read_text(encoding="utf-8")
178
+ )
179
+
180
+ empty_results = json.loads(
181
+ json.dumps(results_fixture, ensure_ascii=False)
182
+ )
183
+ empty_results["platforms"] = []
184
+ empty_results_path = root / "empty-results.json"
185
+ write_json(empty_results_path, empty_results)
186
+ rejected = run_failed(
187
+ command(
188
+ "prepare-comparison",
189
+ "--results",
190
+ str(empty_results_path),
191
+ "--run-dir",
192
+ str(root / "empty-run"),
193
+ )
194
+ )
195
+ assert "至少需要 1 个采集平台" in rejected["error"]
196
+
197
+ single_results = json.loads(
198
+ json.dumps(results_fixture, ensure_ascii=False)
199
+ )
200
+ single_results["platforms"] = single_results["platforms"][:1]
201
+ single_analysis = json.loads(
202
+ json.dumps(analysis_fixture, ensure_ascii=False)
203
+ )
204
+ single_point = single_analysis["knowledgePoints"][0]
205
+ single_point["claims"] = {
206
+ "dknowc-chat": single_point["claims"]["dknowc-chat"]
207
+ }
208
+ single_point["comparison"] = {
209
+ "status": "single",
210
+ "summary": "深知晓单平台知识点结构化结果",
211
+ }
212
+ single_analysis["synthesisDraft"] = {
213
+ "status": "unverified",
214
+ "answer": "深知晓给出的综合草案为每人每月最高提取1400元,尚未经过后续权威核验。",
215
+ "basisKnowledgePointIds": ["K1"],
216
+ }
217
+ single_assessment = json.loads(
218
+ json.dumps(assessment_fixture, ensure_ascii=False)
219
+ )
220
+ single_assessment["verdicts"] = {
221
+ "dknowc-chat": single_assessment["verdicts"]["dknowc-chat"]
222
+ }
223
+ single_run = complete_pipeline(
224
+ root,
225
+ "single-platform",
226
+ single_results,
227
+ single_analysis,
228
+ single_assessment,
229
+ )
230
+ single_comparison = json.loads(
231
+ (single_run / "comparison.json").read_text(encoding="utf-8")
232
+ )
233
+ assert [item["platform"] for item in single_comparison["platforms"]] == [
234
+ "dknowc-chat"
235
+ ]
236
+ assert (
237
+ single_comparison["knowledgePoints"][0]["comparison"]["status"]
238
+ == "single"
239
+ )
240
+ single_verification = json.loads(
241
+ (single_run / "verification.json").read_text(encoding="utf-8")
242
+ )
243
+ assert [item["platform"] for item in single_verification["platforms"]] == [
244
+ "dknowc-chat"
245
+ ]
246
+ assert set(
247
+ single_verification["knowledgePoints"][0]["authority"]["verdicts"]
248
+ ) == {"dknowc-chat"}
249
+ for report_name in ("02-comparison-report.html", "04-final-report.html"):
250
+ report = (single_run / report_name).read_text(encoding="utf-8")
251
+ assert "深知晓" in report
252
+ assert "豆包" not in report
253
+ authority_report = (single_run / "03-authority-report.html").read_text(
254
+ encoding="utf-8"
255
+ )
256
+ assert "权威核验后的最终答案" in authority_report
257
+ assert "深知晓" not in authority_report and "豆包" not in authority_report
258
+ single_comparison_html = (
259
+ single_run / "02-comparison-report.html"
260
+ ).read_text(encoding="utf-8")
261
+ assert single_comparison_html.count('class="answer-panel"') == 1
262
+ assert "各方答案聚合(问题:" in single_comparison_html
263
+ assert "逐知识点结构化结果" in single_comparison_html
264
+ assert "<th>差异</th>" not in single_comparison_html
265
+ assert "跨平台" not in single_comparison_html
266
+
267
+ results = json.loads(json.dumps(results_fixture, ensure_ascii=False))
268
+ deepseek = json.loads(json.dumps(results["platforms"][1], ensure_ascii=False))
269
+ deepseek.update(
270
+ {
271
+ "platform": "deepseek",
272
+ "label": "DeepSeek",
273
+ "url": "https://chat.deepseek.com/",
274
+ "answerMarkdown": "每人每月最高提取 2000 元。",
275
+ }
276
+ )
277
+ results["platforms"].append(deepseek)
278
+
279
+ analysis = json.loads(
280
+ json.dumps(analysis_fixture, ensure_ascii=False)
281
+ )
282
+ analysis["knowledgePoints"][0]["claims"]["deepseek"] = json.loads(
283
+ json.dumps(
284
+ analysis["knowledgePoints"][0]["claims"]["doubao"],
285
+ ensure_ascii=False,
286
+ )
287
+ )
288
+ assessment = json.loads(
289
+ json.dumps(assessment_fixture, ensure_ascii=False)
290
+ )
291
+ assessment["verdicts"]["deepseek"] = json.loads(
292
+ json.dumps(assessment["verdicts"]["doubao"], ensure_ascii=False)
293
+ )
294
+ run_dir = complete_pipeline(
295
+ root,
296
+ "three-platform",
297
+ results,
298
+ analysis,
299
+ assessment,
300
+ )
301
+ comparison = json.loads(
302
+ (run_dir / "comparison.json").read_text(encoding="utf-8")
303
+ )
304
+ assert [item["platform"] for item in comparison["platforms"]] == [
305
+ "dknowc-chat",
306
+ "doubao",
307
+ "deepseek",
308
+ ]
309
+ comparison_html = (run_dir / "comparison.html").read_text(encoding="utf-8")
310
+ assert comparison_html.count('class="answer-panel"') == 3
311
+ assert "DeepSeek" in comparison_html
312
+
313
+ verification = json.loads(
314
+ (run_dir / "verification.json").read_text(encoding="utf-8")
315
+ )
316
+ assert [item["platform"] for item in verification["platforms"]] == [
317
+ "dknowc-chat",
318
+ "doubao",
319
+ "deepseek",
320
+ ]
321
+ final_html = (run_dir / "report.html").read_text(encoding="utf-8")
322
+ authority_html = (run_dir / "03-authority-report.html").read_text(
323
+ encoding="utf-8"
324
+ )
325
+ capture_html = (run_dir / "01-capture-report.html").read_text(
326
+ encoding="utf-8"
327
+ )
328
+ assert "DeepSeek" in final_html
329
+ assert "权威核验后的最终答案" in authority_html
330
+ assert "DeepSeek" not in authority_html
331
+ assert (
332
+ 'class="shell platform-layout-compact platform-count-3" '
333
+ 'style="--platform-count:3"'
334
+ ) in capture_html
335
+ assert "repeat(var(--platform-count), minmax(0, 1fr))" in capture_html
336
+ assert "repeat(3, 500px)" not in capture_html
337
+ assert (
338
+ '<main class="multi-platform platform-layout-compact '
339
+ 'platform-count-3" style="--platform-count:3">'
340
+ ) in comparison_html
341
+ assert (
342
+ '<body class="platform-layout-compact platform-count-3" '
343
+ 'style="--platform-count:3;'
344
+ ) in final_html
345
+ assert 'class="locked-platforms"' in final_html
346
+ assert ".locked-platforms{display:grid" in final_html
347
+ assert "② 逐知识点核验明细" in final_html
348
+ assert final_html.count("② 逐知识点核验明细") == 1
349
+ assert 'data-fcx-locked-role="direct"' in final_html
350
+ assert 'data-fcx-locked-role="reference"' in final_html
351
+ assert "② 直接答案逐知识点测评" not in final_html
352
+ assert "③ 补充参考逐知识点测评" not in final_html
353
+
354
+ if os.getenv("FACT_CHECK_X_ASSERTIONS_OUTPUT"):
355
+ Path(os.environ["FACT_CHECK_X_ASSERTIONS_OUTPUT"]).write_text(json.dumps({
356
+ "schemaVersion": "fact-check-x/test-assertions@1",
357
+ "actualAssertionIds": [
358
+ "platform.minimum_one",
359
+ "platform.single_full_pipeline",
360
+ "platform.three_full_pipeline",
361
+ "platform.dynamic_layout",
362
+ ],
363
+ }), encoding="utf-8")
364
+ print("PASS Fact-Check-X N≥1 动态单/多平台完整流水线")
365
+ return 0
366
+
367
+
368
+ if __name__ == "__main__":
369
+ raise SystemExit(main())