opencode-skills-collection 4.0.68 → 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 (491) hide show
  1. package/bundled-skills/.antigravity-install-manifest.json +304 -1
  2. package/bundled-skills/access-review/SKILL.md +394 -0
  3. package/bundled-skills/access-review/references/details.md +121 -0
  4. package/bundled-skills/agent-evals/SKILL.md +420 -0
  5. package/bundled-skills/agent-observability/SKILL.md +346 -0
  6. package/bundled-skills/agent-observability/references/details.md +786 -0
  7. package/bundled-skills/ai-agent-security/SKILL.md +393 -0
  8. package/bundled-skills/ai-agent-security/references/details.md +912 -0
  9. package/bundled-skills/ai-coding-agent-guardrails/SKILL.md +442 -0
  10. package/bundled-skills/ai-coding-agent-guardrails/references/details.md +753 -0
  11. package/bundled-skills/ai-inference-service-mesh/SKILL.md +449 -0
  12. package/bundled-skills/ai-pipeline-orchestration/SKILL.md +287 -0
  13. package/bundled-skills/ai-red-teaming/SKILL.md +409 -0
  14. package/bundled-skills/ai-security-hardening/SKILL.md +343 -0
  15. package/bundled-skills/ai-sre-incident-response/SKILL.md +336 -0
  16. package/bundled-skills/alerting-oncall/SKILL.md +458 -0
  17. package/bundled-skills/alerting-oncall/references/details.md +84 -0
  18. package/bundled-skills/api-integration-architect/SKILL.md +241 -0
  19. package/bundled-skills/apify-generate-output-schema/SKILL.md +438 -0
  20. package/bundled-skills/apify-integration-development/SKILL.md +168 -0
  21. package/bundled-skills/apify-integration-development/references/ai-framework-package.md +158 -0
  22. package/bundled-skills/apify-integration-development/references/ai-harness-plugin.md +192 -0
  23. package/bundled-skills/apify-integration-development/references/sdk-integration.md +236 -0
  24. package/bundled-skills/apify-integration-development/references/workflow-automation.md +163 -0
  25. package/bundled-skills/apk-redteam-pipeline/SKILL.md +446 -0
  26. package/bundled-skills/architecture-review/README.md +42 -0
  27. package/bundled-skills/architecture-review/SKILL.md +77 -0
  28. package/bundled-skills/architecture-review/examples.md +11 -0
  29. package/bundled-skills/architecture-review/reference/best-practices.md +7 -0
  30. package/bundled-skills/architecture-review/reference/capabilities.md +20 -0
  31. package/bundled-skills/architecture-review/reference/fallbacks.md +11 -0
  32. package/bundled-skills/architecture-review/reference/graph.md +15 -0
  33. package/bundled-skills/architecture-review/reference/mcp.md +14 -0
  34. package/bundled-skills/architecture-review/reference/workflow.md +15 -0
  35. package/bundled-skills/architecture-review/templates/architecture-review.md +21 -0
  36. package/bundled-skills/argocd-gitops/SKILL.md +469 -0
  37. package/bundled-skills/arm-templates/SKILL.md +438 -0
  38. package/bundled-skills/arm-templates/references/details.md +64 -0
  39. package/bundled-skills/asset-inventory/SKILL.md +412 -0
  40. package/bundled-skills/asset-inventory/references/details.md +127 -0
  41. package/bundled-skills/audit-logging/SKILL.md +476 -0
  42. package/bundled-skills/aws-cloudtrail/SKILL.md +486 -0
  43. package/bundled-skills/aws-cost-optimization/SKILL.md +331 -0
  44. package/bundled-skills/aws-ec2/SKILL.md +426 -0
  45. package/bundled-skills/aws-ecs-fargate/SKILL.md +388 -0
  46. package/bundled-skills/aws-iam/SKILL.md +463 -0
  47. package/bundled-skills/aws-lambda/SKILL.md +428 -0
  48. package/bundled-skills/aws-rds/SKILL.md +380 -0
  49. package/bundled-skills/aws-s3/SKILL.md +434 -0
  50. package/bundled-skills/aws-secrets-manager/SKILL.md +486 -0
  51. package/bundled-skills/aws-vpc/SKILL.md +436 -0
  52. package/bundled-skills/azure-ai-document-intelligence-ts/SKILL.md +1 -1
  53. package/bundled-skills/azure-aks/SKILL.md +423 -0
  54. package/bundled-skills/azure-devops/SKILL.md +457 -0
  55. package/bundled-skills/azure-functions-devsec/SKILL.md +436 -0
  56. package/bundled-skills/azure-keyvault/SKILL.md +455 -0
  57. package/bundled-skills/azure-keyvault/references/details.md +83 -0
  58. package/bundled-skills/azure-monitor-audit/SKILL.md +379 -0
  59. package/bundled-skills/azure-networking/SKILL.md +448 -0
  60. package/bundled-skills/azure-networking/references/details.md +135 -0
  61. package/bundled-skills/azure-sql/SKILL.md +413 -0
  62. package/bundled-skills/azure-sql/references/details.md +113 -0
  63. package/bundled-skills/azure-vms/SKILL.md +402 -0
  64. package/bundled-skills/azure-vms/references/details.md +134 -0
  65. package/bundled-skills/backup-recovery/SKILL.md +388 -0
  66. package/bundled-skills/bb-methodology/SKILL.md +451 -0
  67. package/bundled-skills/bb-methodology/references/details.md +120 -0
  68. package/bundled-skills/block-storage/SKILL.md +371 -0
  69. package/bundled-skills/blue-green-deploy/SKILL.md +453 -0
  70. package/bundled-skills/blue-green-deploy/references/details.md +90 -0
  71. package/bundled-skills/bug-bounty/SKILL.md +447 -0
  72. package/bundled-skills/bug-bounty/references/details.md +1316 -0
  73. package/bundled-skills/bugcrowd-reporting/SKILL.md +351 -0
  74. package/bundled-skills/business-continuity/SKILL.md +463 -0
  75. package/bundled-skills/career-ops/SKILL.md +186 -0
  76. package/bundled-skills/cdn-setup/SKILL.md +374 -0
  77. package/bundled-skills/change-management/SKILL.md +438 -0
  78. package/bundled-skills/change-management/references/details.md +105 -0
  79. package/bundled-skills/circleci/SKILL.md +475 -0
  80. package/bundled-skills/cis-benchmarks/SKILL.md +150 -0
  81. package/bundled-skills/cloudflare-pages/SKILL.md +318 -0
  82. package/bundled-skills/cloudflare-r2/SKILL.md +353 -0
  83. package/bundled-skills/cloudflare-workers/SKILL.md +415 -0
  84. package/bundled-skills/cloudflare-zero-trust/SKILL.md +361 -0
  85. package/bundled-skills/cloudformation/SKILL.md +461 -0
  86. package/bundled-skills/code-review-sensei/SKILL.md +177 -0
  87. package/bundled-skills/codebase-onboarding/README.md +42 -0
  88. package/bundled-skills/codebase-onboarding/SKILL.md +77 -0
  89. package/bundled-skills/codebase-onboarding/examples.md +11 -0
  90. package/bundled-skills/codebase-onboarding/reference/best-practices.md +7 -0
  91. package/bundled-skills/codebase-onboarding/reference/capabilities.md +20 -0
  92. package/bundled-skills/codebase-onboarding/reference/fallbacks.md +11 -0
  93. package/bundled-skills/codebase-onboarding/reference/graph.md +15 -0
  94. package/bundled-skills/codebase-onboarding/reference/mcp.md +14 -0
  95. package/bundled-skills/codebase-onboarding/reference/workflow.md +15 -0
  96. package/bundled-skills/codebase-onboarding/templates/repository-onboarding.md +21 -0
  97. package/bundled-skills/connection-auth-rules/SKILL.md +199 -0
  98. package/bundled-skills/connection-auth-rules/fetch_schema.py +320 -0
  99. package/bundled-skills/constraint-driven-development/SKILL.md +335 -0
  100. package/bundled-skills/constraint-driven-development/references/floor-guard.md +99 -0
  101. package/bundled-skills/container-hardening/SKILL.md +126 -0
  102. package/bundled-skills/container-registries/SKILL.md +435 -0
  103. package/bundled-skills/container-scanning/SKILL.md +416 -0
  104. package/bundled-skills/convex-backend/SKILL.md +338 -0
  105. package/bundled-skills/dast-scanning/SKILL.md +437 -0
  106. package/bundled-skills/database-backups/SKILL.md +425 -0
  107. package/bundled-skills/datadog/SKILL.md +487 -0
  108. package/bundled-skills/dependency-analysis/README.md +42 -0
  109. package/bundled-skills/dependency-analysis/SKILL.md +76 -0
  110. package/bundled-skills/dependency-analysis/examples.md +11 -0
  111. package/bundled-skills/dependency-analysis/reference/best-practices.md +7 -0
  112. package/bundled-skills/dependency-analysis/reference/capabilities.md +20 -0
  113. package/bundled-skills/dependency-analysis/reference/fallbacks.md +11 -0
  114. package/bundled-skills/dependency-analysis/reference/graph.md +15 -0
  115. package/bundled-skills/dependency-analysis/reference/mcp.md +14 -0
  116. package/bundled-skills/dependency-analysis/reference/workflow.md +15 -0
  117. package/bundled-skills/dependency-analysis/templates/dependency-review.md +21 -0
  118. package/bundled-skills/dependency-scanning/SKILL.md +457 -0
  119. package/bundled-skills/devcontainers-nix/SKILL.md +416 -0
  120. package/bundled-skills/devops-pipeline-builder/SKILL.md +200 -0
  121. package/bundled-skills/disaster-recovery/SKILL.md +374 -0
  122. package/bundled-skills/disaster-recovery/references/details.md +219 -0
  123. package/bundled-skills/dns-management/SKILL.md +375 -0
  124. package/bundled-skills/docker-compose/SKILL.md +482 -0
  125. package/bundled-skills/docker-management/SKILL.md +426 -0
  126. package/bundled-skills/eas-app-stores/SKILL.md +197 -0
  127. package/bundled-skills/eas-app-stores/agents/openai.yaml +4 -0
  128. package/bundled-skills/eas-app-stores/references/app-store-metadata.md +497 -0
  129. package/bundled-skills/eas-app-stores/references/ios-app-store.md +376 -0
  130. package/bundled-skills/eas-app-stores/references/native-ios.md +167 -0
  131. package/bundled-skills/eas-app-stores/references/play-store.md +244 -0
  132. package/bundled-skills/eas-app-stores/references/testflight.md +62 -0
  133. package/bundled-skills/eas-app-stores/references/workflows.md +120 -0
  134. package/bundled-skills/eas-hosting/SKILL.md +448 -0
  135. package/bundled-skills/eas-hosting/agents/openai.yaml +4 -0
  136. package/bundled-skills/eas-observe/SKILL.md +75 -0
  137. package/bundled-skills/eas-observe/agents/openai.yaml +4 -0
  138. package/bundled-skills/eas-observe/references/metrics.md +98 -0
  139. package/bundled-skills/eas-observe/references/queries.md +403 -0
  140. package/bundled-skills/eas-observe/references/setup.md +476 -0
  141. package/bundled-skills/eas-observe/references/third-party.md +136 -0
  142. package/bundled-skills/eas-simulator/SKILL.md +251 -0
  143. package/bundled-skills/eas-simulator/agents/openai.yaml +4 -0
  144. package/bundled-skills/eas-simulator/references/controllers.md +135 -0
  145. package/bundled-skills/eas-simulator/references/run-your-app.md +240 -0
  146. package/bundled-skills/eas-simulator/references/troubleshooting.md +47 -0
  147. package/bundled-skills/eas-workflows/SKILL.md +119 -0
  148. package/bundled-skills/eas-workflows/agents/openai.yaml +4 -0
  149. package/bundled-skills/eas-workflows/scripts/fetch.js +109 -0
  150. package/bundled-skills/ebpf-observability/SKILL.md +436 -0
  151. package/bundled-skills/ebpf-observability/references/details.md +542 -0
  152. package/bundled-skills/elk-stack/SKILL.md +487 -0
  153. package/bundled-skills/enterprise-vpn-attack/SKILL.md +395 -0
  154. package/bundled-skills/evidence-hygiene/SKILL.md +404 -0
  155. package/bundled-skills/expo-animation/LICENSE +21 -0
  156. package/bundled-skills/expo-animation/RECIPES.md +385 -0
  157. package/bundled-skills/expo-animation/SKILL.md +295 -0
  158. package/bundled-skills/expo-animation/agents/openai.yaml +4 -0
  159. package/bundled-skills/fact-check-x-unified/SKILL.md +178 -0
  160. package/bundled-skills/fact-check-x-unified/agents/openai.yaml +4 -0
  161. package/bundled-skills/fact-check-x-unified/references/acceptance-criteria.md +44 -0
  162. package/bundled-skills/fact-check-x-unified/references/contracts.md +39 -0
  163. package/bundled-skills/fact-check-x-unified/scripts/common.py +31 -0
  164. package/bundled-skills/fact-check-x-unified/scripts/fact_check_x.py +1832 -0
  165. package/bundled-skills/fact-check-x-unified/scripts/trusted_search_config.py +324 -0
  166. package/bundled-skills/fact-check-x-unified/tests/anchor_downgrade_test.py +90 -0
  167. package/bundled-skills/fact-check-x-unified/tests/multi_platform_test.py +369 -0
  168. package/bundled-skills/fact-check-x-unified/tests/smoke_test.py +740 -0
  169. package/bundled-skills/fact-check-x-unified/tests/stage_checkpoint_test.py +103 -0
  170. package/bundled-skills/fact-check-x-unified/tests/trusted_search_config_test.py +156 -0
  171. package/bundled-skills/feature-flags/SKILL.md +426 -0
  172. package/bundled-skills/feature-flags/references/details.md +86 -0
  173. package/bundled-skills/fedramp-compliance/SKILL.md +453 -0
  174. package/bundled-skills/firebase-app-platform/SKILL.md +381 -0
  175. package/bundled-skills/firewall-config/SKILL.md +479 -0
  176. package/bundled-skills/gcp-audit-logs/SKILL.md +452 -0
  177. package/bundled-skills/gcp-audit-logs/references/details.md +56 -0
  178. package/bundled-skills/gcp-cloud-functions/SKILL.md +284 -0
  179. package/bundled-skills/gcp-cloud-sql/SKILL.md +277 -0
  180. package/bundled-skills/gcp-compute/SKILL.md +319 -0
  181. package/bundled-skills/gcp-gke/SKILL.md +307 -0
  182. package/bundled-skills/gcp-networking/SKILL.md +293 -0
  183. package/bundled-skills/gcp-secret-manager/SKILL.md +421 -0
  184. package/bundled-skills/gcp-secret-manager/references/details.md +131 -0
  185. package/bundled-skills/gdpr-compliance/SKILL.md +451 -0
  186. package/bundled-skills/gdpr-compliance/references/details.md +145 -0
  187. package/bundled-skills/geo-audit/SKILL.md +368 -0
  188. package/bundled-skills/geo-brand-mentions/SKILL.md +68 -0
  189. package/bundled-skills/geo-brand-mentions/references/details.md +471 -0
  190. package/bundled-skills/geo-citability/SKILL.md +350 -0
  191. package/bundled-skills/geo-compare/SKILL.md +340 -0
  192. package/bundled-skills/geo-content/SKILL.md +383 -0
  193. package/bundled-skills/geo-crawlers/SKILL.md +408 -0
  194. package/bundled-skills/geo-llmstxt/SKILL.md +464 -0
  195. package/bundled-skills/geo-platform-optimizer/SKILL.md +314 -0
  196. package/bundled-skills/geo-proposal/SKILL.md +378 -0
  197. package/bundled-skills/geo-prospect/SKILL.md +225 -0
  198. package/bundled-skills/geo-report/SKILL.md +436 -0
  199. package/bundled-skills/geo-report-pdf/SKILL.md +157 -0
  200. package/bundled-skills/geo-schema/SKILL.md +408 -0
  201. package/bundled-skills/geo-technical/SKILL.md +78 -0
  202. package/bundled-skills/geo-technical/references/details.md +543 -0
  203. package/bundled-skills/git-workflow/SKILL.md +460 -0
  204. package/bundled-skills/github-actions/SKILL.md +368 -0
  205. package/bundled-skills/gitlab-ci/SKILL.md +340 -0
  206. package/bundled-skills/gpt-taste/SKILL.md +8 -1
  207. package/bundled-skills/gpu-kubernetes-operations/SKILL.md +468 -0
  208. package/bundled-skills/gpu-server-management/SKILL.md +236 -0
  209. package/bundled-skills/hashicorp-vault/SKILL.md +408 -0
  210. package/bundled-skills/helm-charts/SKILL.md +469 -0
  211. package/bundled-skills/hf-cli/SKILL.md +263 -0
  212. package/bundled-skills/hipaa-compliance/SKILL.md +451 -0
  213. package/bundled-skills/huggingface-community-evals/SKILL.md +228 -0
  214. package/bundled-skills/huggingface-community-evals/examples/.env.example +3 -0
  215. package/bundled-skills/huggingface-community-evals/examples/USAGE_EXAMPLES.md +101 -0
  216. package/bundled-skills/huggingface-community-evals/scripts/inspect_eval_uv.py +104 -0
  217. package/bundled-skills/huggingface-community-evals/scripts/inspect_vllm_uv.py +306 -0
  218. package/bundled-skills/huggingface-community-evals/scripts/lighteval_vllm_uv.py +297 -0
  219. package/bundled-skills/huggingface-datasets/SKILL.md +130 -0
  220. package/bundled-skills/hunt-aspnet/SKILL.md +321 -0
  221. package/bundled-skills/hunt-ato/SKILL.md +184 -0
  222. package/bundled-skills/hunt-auth-bypass/SKILL.md +426 -0
  223. package/bundled-skills/hunt-auth-bypass/references/details.md +80 -0
  224. package/bundled-skills/hunt-brute-force/SKILL.md +341 -0
  225. package/bundled-skills/hunt-business-logic/SKILL.md +281 -0
  226. package/bundled-skills/hunt-cache-poison/SKILL.md +382 -0
  227. package/bundled-skills/hunt-captcha-bypass/SKILL.md +136 -0
  228. package/bundled-skills/hunt-cicd/SKILL.md +311 -0
  229. package/bundled-skills/hunt-clickjacking/SKILL.md +110 -0
  230. package/bundled-skills/hunt-cors/SKILL.md +335 -0
  231. package/bundled-skills/hunt-dom/SKILL.md +323 -0
  232. package/bundled-skills/hunt-exceptional-conditions/SKILL.md +111 -0
  233. package/bundled-skills/hunt-file-upload/SKILL.md +202 -0
  234. package/bundled-skills/hunt-fintech-graphql/SKILL.md +289 -0
  235. package/bundled-skills/hunt-forgot-password/SKILL.md +114 -0
  236. package/bundled-skills/hunt-grpc/SKILL.md +317 -0
  237. package/bundled-skills/hunt-host-header/SKILL.md +309 -0
  238. package/bundled-skills/hunt-html-injection/SKILL.md +106 -0
  239. package/bundled-skills/hunt-http-smuggling/SKILL.md +129 -0
  240. package/bundled-skills/hunt-http-smuggling/references/phase2h-smuggling-cachepoison.md +177 -0
  241. package/bundled-skills/hunt-idor/SKILL.md +434 -0
  242. package/bundled-skills/hunt-jwt-crypto/SKILL.md +221 -0
  243. package/bundled-skills/hunt-k8s/SKILL.md +337 -0
  244. package/bundled-skills/hunt-laravel/SKILL.md +255 -0
  245. package/bundled-skills/hunt-ldap/SKILL.md +351 -0
  246. package/bundled-skills/hunt-lfi/SKILL.md +311 -0
  247. package/bundled-skills/hunt-llm-ai/SKILL.md +289 -0
  248. package/bundled-skills/hunt-mfa-bypass/SKILL.md +177 -0
  249. package/bundled-skills/hunt-misc/SKILL.md +378 -0
  250. package/bundled-skills/hunt-nextjs/SKILL.md +299 -0
  251. package/bundled-skills/hunt-nodejs/SKILL.md +263 -0
  252. package/bundled-skills/hunt-nosqli/SKILL.md +210 -0
  253. package/bundled-skills/hunt-ntlm-info/SKILL.md +314 -0
  254. package/bundled-skills/hunt-oauth/SKILL.md +459 -0
  255. package/bundled-skills/hunt-open-redirect/SKILL.md +223 -0
  256. package/bundled-skills/hunt-race-condition/SKILL.md +381 -0
  257. package/bundled-skills/hunt-race-condition/references/details.md +159 -0
  258. package/bundled-skills/hunt-rag-vector/SKILL.md +212 -0
  259. package/bundled-skills/hunt-rce/SKILL.md +444 -0
  260. package/bundled-skills/hunt-rce/references/details.md +110 -0
  261. package/bundled-skills/hunt-saml/SKILL.md +156 -0
  262. package/bundled-skills/hunt-session/SKILL.md +342 -0
  263. package/bundled-skills/hunt-shadow-api/SKILL.md +198 -0
  264. package/bundled-skills/hunt-source-leak/SKILL.md +345 -0
  265. package/bundled-skills/hunt-spa-api/SKILL.md +163 -0
  266. package/bundled-skills/hunt-springboot/SKILL.md +285 -0
  267. package/bundled-skills/hunt-sqli/SKILL.md +466 -0
  268. package/bundled-skills/hunt-ssrf/SKILL.md +396 -0
  269. package/bundled-skills/hunt-ssrf/references/details.md +179 -0
  270. package/bundled-skills/hunt-ssti/SKILL.md +163 -0
  271. package/bundled-skills/hunt-subdomain/SKILL.md +379 -0
  272. package/bundled-skills/hunt-tls-network/SKILL.md +399 -0
  273. package/bundled-skills/hunt-xxe/SKILL.md +466 -0
  274. package/bundled-skills/i-have-adhd/SKILL.md +170 -0
  275. package/bundled-skills/identity-access-management/SKILL.md +382 -0
  276. package/bundled-skills/identity-access-management/references/details.md +524 -0
  277. package/bundled-skills/incident-management/SKILL.md +484 -0
  278. package/bundled-skills/incident-response/SKILL.md +448 -0
  279. package/bundled-skills/incident-response/references/details.md +113 -0
  280. package/bundled-skills/interview-me/SKILL.md +248 -0
  281. package/bundled-skills/iso27001-compliance/SKILL.md +460 -0
  282. package/bundled-skills/jenkins/SKILL.md +462 -0
  283. package/bundled-skills/jev-social/SKILL.md +182 -0
  284. package/bundled-skills/jev-use/SKILL.md +158 -0
  285. package/bundled-skills/kubernetes-hardening/SKILL.md +154 -0
  286. package/bundled-skills/kubernetes-ops/SKILL.md +449 -0
  287. package/bundled-skills/kubernetes-ops/references/details.md +108 -0
  288. package/bundled-skills/kustomize/SKILL.md +478 -0
  289. package/bundled-skills/linux-administration/SKILL.md +367 -0
  290. package/bundled-skills/linux-hardening/SKILL.md +154 -0
  291. package/bundled-skills/llm-app-security/SKILL.md +389 -0
  292. package/bundled-skills/llm-app-security/references/details.md +674 -0
  293. package/bundled-skills/llm-caching/SKILL.md +334 -0
  294. package/bundled-skills/llm-cost-optimization/SKILL.md +311 -0
  295. package/bundled-skills/llm-fine-tuning/SKILL.md +329 -0
  296. package/bundled-skills/llm-gateway/SKILL.md +282 -0
  297. package/bundled-skills/llm-inference-scaling/SKILL.md +286 -0
  298. package/bundled-skills/llmops-platform-engineering/SKILL.md +472 -0
  299. package/bundled-skills/load-balancing/SKILL.md +403 -0
  300. package/bundled-skills/loki-logging/SKILL.md +479 -0
  301. package/bundled-skills/longbridge-derivatives/SKILL.md +117 -0
  302. package/bundled-skills/longbridge-derivatives/references/option.md +36 -0
  303. package/bundled-skills/longbridge-derivatives/references/options-advanced.md +101 -0
  304. package/bundled-skills/longbridge-derivatives/references/options-pnl.md +74 -0
  305. package/bundled-skills/longbridge-derivatives/references/options-strategy.md +82 -0
  306. package/bundled-skills/longbridge-derivatives/references/options-volatility.md +70 -0
  307. package/bundled-skills/longbridge-derivatives/references/warrant.md +12 -0
  308. package/bundled-skills/longbridge-quant/SKILL.md +151 -0
  309. package/bundled-skills/longbridge-quant/references/correlation.md +51 -0
  310. package/bundled-skills/longbridge-quant/references/execution-model.md +68 -0
  311. package/bundled-skills/longbridge-quant/references/factor-research.md +95 -0
  312. package/bundled-skills/longbridge-quant/references/factor-screen.md +101 -0
  313. package/bundled-skills/longbridge-quant/references/hedging.md +136 -0
  314. package/bundled-skills/longbridge-quant/references/ml-strategy.md +77 -0
  315. package/bundled-skills/longbridge-quant/references/multifactor.md +68 -0
  316. package/bundled-skills/longbridge-quant/references/pairs-trading.md +61 -0
  317. package/bundled-skills/longbridge-quant/references/quant-cli.md +133 -0
  318. package/bundled-skills/longbridge-quant/references/quant-stats.md +150 -0
  319. package/bundled-skills/longbridge-quant/references/seasonality.md +50 -0
  320. package/bundled-skills/longbridge-quant/references/strategy-optimizer.md +68 -0
  321. package/bundled-skills/longbridge-quant/references/volatility-strategy.md +52 -0
  322. package/bundled-skills/longbridge-research/SKILL.md +187 -0
  323. package/bundled-skills/longbridge-research/references/company-profile.md +96 -0
  324. package/bundled-skills/longbridge-research/references/company-tearsheet.md +82 -0
  325. package/bundled-skills/longbridge-research/references/competitive-analysis.md +81 -0
  326. package/bundled-skills/longbridge-research/references/consensus.md +92 -0
  327. package/bundled-skills/longbridge-research/references/coverage-initiation.md +76 -0
  328. package/bundled-skills/longbridge-research/references/defi-yield.md +60 -0
  329. package/bundled-skills/longbridge-research/references/finance-calendar.md +165 -0
  330. package/bundled-skills/longbridge-research/references/financial-planning.md +77 -0
  331. package/bundled-skills/longbridge-research/references/forecast-eps.md +39 -0
  332. package/bundled-skills/longbridge-research/references/fund-holder.md +44 -0
  333. package/bundled-skills/longbridge-research/references/hkipo-analysis.md +101 -0
  334. package/bundled-skills/longbridge-research/references/industry-peers.md +46 -0
  335. package/bundled-skills/longbridge-research/references/industry-rank.md +62 -0
  336. package/bundled-skills/longbridge-research/references/insider-trades.md +48 -0
  337. package/bundled-skills/longbridge-research/references/institution-rating.md +62 -0
  338. package/bundled-skills/longbridge-research/references/investment-ideas.md +69 -0
  339. package/bundled-skills/longbridge-research/references/investment-proposal.md +95 -0
  340. package/bundled-skills/longbridge-research/references/investors.md +87 -0
  341. package/bundled-skills/longbridge-research/references/onchain.md +70 -0
  342. package/bundled-skills/longbridge-research/references/post-investment.md +76 -0
  343. package/bundled-skills/longbridge-research/references/shareholder.md +72 -0
  344. package/bundled-skills/longbridge-research/references/short-positions.md +50 -0
  345. package/bundled-skills/longbridge-research/references/short-trades.md +50 -0
  346. package/bundled-skills/longbridge-research/references/stock-research.md +61 -0
  347. package/bundled-skills/longbridge-research/references/thesis-tracker.md +64 -0
  348. package/bundled-skills/m365-entra-attack/SKILL.md +423 -0
  349. package/bundled-skills/mac-mini-llm-lab/SKILL.md +350 -0
  350. package/bundled-skills/makepad-2-0-animation/SKILL.md +318 -0
  351. package/bundled-skills/makepad-2-0-animation/references/animator-reference.md +433 -0
  352. package/bundled-skills/makepad-2-0-dsl/SKILL.md +492 -0
  353. package/bundled-skills/makepad-2-0-dsl/references/dsl-syntax-reference.md +511 -0
  354. package/bundled-skills/makepad-2-0-dsl/references/extended-guide.md +56 -0
  355. package/bundled-skills/makepad-2-0-dsl/references/property-system.md +757 -0
  356. package/bundled-skills/makepad-2-0-events/SKILL.md +497 -0
  357. package/bundled-skills/makepad-2-0-events/references/event-patterns.md +802 -0
  358. package/bundled-skills/makepad-2-0-events/references/extended-guide.md +590 -0
  359. package/bundled-skills/makepad-2-0-layout/SKILL.md +499 -0
  360. package/bundled-skills/makepad-2-0-layout/references/extended-guide.md +243 -0
  361. package/bundled-skills/makepad-2-0-layout/references/layout-patterns.md +881 -0
  362. package/bundled-skills/makepad-2-0-widgets/SKILL.md +261 -0
  363. package/bundled-skills/makepad-2-0-widgets/references/widget-advanced.md +648 -0
  364. package/bundled-skills/makepad-2-0-widgets/references/widget-catalog.md +547 -0
  365. package/bundled-skills/mcp-server-security/SKILL.md +356 -0
  366. package/bundled-skills/mcp-server-security/references/details.md +745 -0
  367. package/bundled-skills/mdm-device-management/SKILL.md +404 -0
  368. package/bundled-skills/mdm-device-management/references/details.md +410 -0
  369. package/bundled-skills/meeting-distiller-pro/SKILL.md +120 -0
  370. package/bundled-skills/meme-coin-audit/SKILL.md +402 -0
  371. package/bundled-skills/mid-engagement-ir-detection/SKILL.md +377 -0
  372. package/bundled-skills/model-registry-governance/SKILL.md +452 -0
  373. package/bundled-skills/model-serving-kubernetes/SKILL.md +339 -0
  374. package/bundled-skills/model-supply-chain-security/SKILL.md +427 -0
  375. package/bundled-skills/mongodb/SKILL.md +436 -0
  376. package/bundled-skills/monte-carlo-analyze-root-cause/SKILL.md +12 -1
  377. package/bundled-skills/monte-carlo-asset-health/SKILL.md +12 -1
  378. package/bundled-skills/monte-carlo-context-detection/SKILL.md +170 -0
  379. package/bundled-skills/monte-carlo-context-detection/references/signal-definitions.md +46 -0
  380. package/bundled-skills/multi-tenant-llm-hosting/SKILL.md +435 -0
  381. package/bundled-skills/multi-tenant-llm-hosting/references/details.md +211 -0
  382. package/bundled-skills/mysql/SKILL.md +390 -0
  383. package/bundled-skills/new-relic/SKILL.md +472 -0
  384. package/bundled-skills/nfs-storage/SKILL.md +356 -0
  385. package/bundled-skills/object-storage/SKILL.md +378 -0
  386. package/bundled-skills/offensive-osint/SKILL.md +443 -0
  387. package/bundled-skills/okta-attack/SKILL.md +436 -0
  388. package/bundled-skills/ollama-stack/SKILL.md +379 -0
  389. package/bundled-skills/openclaw-deployment-hardening/SKILL.md +135 -0
  390. package/bundled-skills/openclaw-local-mac-mini/SKILL.md +426 -0
  391. package/bundled-skills/openclaw-local-mac-mini/references/details.md +221 -0
  392. package/bundled-skills/openclaw-security-hardening/SKILL.md +135 -0
  393. package/bundled-skills/openshift/SKILL.md +485 -0
  394. package/bundled-skills/opentelemetry/SKILL.md +438 -0
  395. package/bundled-skills/opentelemetry/references/details.md +78 -0
  396. package/bundled-skills/opentofu-migration/SKILL.md +349 -0
  397. package/bundled-skills/osint-methodology/SKILL.md +460 -0
  398. package/bundled-skills/osint-methodology/references/details.md +1350 -0
  399. package/bundled-skills/pci-dss-compliance/SKILL.md +446 -0
  400. package/bundled-skills/penetration-testing/SKILL.md +152 -0
  401. package/bundled-skills/performance-tuning/SKILL.md +381 -0
  402. package/bundled-skills/planetscale/SKILL.md +297 -0
  403. package/bundled-skills/platform-engineering/SKILL.md +348 -0
  404. package/bundled-skills/platform-engineering/references/details.md +944 -0
  405. package/bundled-skills/podman/SKILL.md +405 -0
  406. package/bundled-skills/policy-as-code/SKILL.md +434 -0
  407. package/bundled-skills/policy-as-code/references/details.md +204 -0
  408. package/bundled-skills/postgresql-devsec/SKILL.md +378 -0
  409. package/bundled-skills/prometheus-grafana/SKILL.md +469 -0
  410. package/bundled-skills/prompt-injection-defense/SKILL.md +483 -0
  411. package/bundled-skills/rag-infrastructure/SKILL.md +269 -0
  412. package/bundled-skills/rag-observability-evals/SKILL.md +444 -0
  413. package/bundled-skills/rag-observability-evals/references/details.md +92 -0
  414. package/bundled-skills/recon-scope-triage/SKILL.md +128 -0
  415. package/bundled-skills/redis/SKILL.md +421 -0
  416. package/bundled-skills/redteam-report-template/SKILL.md +370 -0
  417. package/bundled-skills/remotion-captions/SKILL.md +57 -0
  418. package/bundled-skills/remotion-captions/agents/openai.yaml +7 -0
  419. package/bundled-skills/remotion-captions/assets/remotion-icon.svg +4 -0
  420. package/bundled-skills/remotion-captions/display-captions.md +190 -0
  421. package/bundled-skills/remotion-captions/import-srt-captions.md +73 -0
  422. package/bundled-skills/remotion-captions/transcribe-captions.md +70 -0
  423. package/bundled-skills/remotion-create/SKILL.md +106 -0
  424. package/bundled-skills/remotion-create/agents/openai.yaml +7 -0
  425. package/bundled-skills/remotion-create/assets/remotion-icon.svg +4 -0
  426. package/bundled-skills/remotion-create/tailwind.md +11 -0
  427. package/bundled-skills/remotion-create/video-layout.md +9 -0
  428. package/bundled-skills/remotion-docs/SKILL.md +67 -0
  429. package/bundled-skills/remotion-docs/agents/openai.yaml +7 -0
  430. package/bundled-skills/remotion-docs/assets/remotion-icon.svg +4 -0
  431. package/bundled-skills/remotion-interactivity/SKILL.md +270 -0
  432. package/bundled-skills/remotion-interactivity/agents/openai.yaml +7 -0
  433. package/bundled-skills/remotion-interactivity/assets/remotion-icon.svg +4 -0
  434. package/bundled-skills/remotion-render/SKILL.md +48 -0
  435. package/bundled-skills/remotion-render/agents/openai.yaml +7 -0
  436. package/bundled-skills/remotion-render/assets/remotion-icon.svg +4 -0
  437. package/bundled-skills/remotion-render/transparent-videos.md +106 -0
  438. package/bundled-skills/report-writing/SKILL.md +426 -0
  439. package/bundled-skills/report-writing/references/details.md +187 -0
  440. package/bundled-skills/reverse-proxy/SKILL.md +420 -0
  441. package/bundled-skills/runbook-creation/SKILL.md +438 -0
  442. package/bundled-skills/runbook-creation/references/details.md +71 -0
  443. package/bundled-skills/saas-pricing-strategist/SKILL.md +169 -0
  444. package/bundled-skills/saas-security-posture/SKILL.md +415 -0
  445. package/bundled-skills/sast-scanning/SKILL.md +444 -0
  446. package/bundled-skills/sbom-supply-chain/SKILL.md +433 -0
  447. package/bundled-skills/score-eval/SKILL.md +35 -0
  448. package/bundled-skills/security-arsenal/SKILL.md +446 -0
  449. package/bundled-skills/security-arsenal/references/details.md +540 -0
  450. package/bundled-skills/security-automation/SKILL.md +146 -0
  451. package/bundled-skills/semantic-versioning/SKILL.md +434 -0
  452. package/bundled-skills/semantic-versioning/references/details.md +83 -0
  453. package/bundled-skills/service-mesh/SKILL.md +422 -0
  454. package/bundled-skills/soc2-compliance/SKILL.md +409 -0
  455. package/bundled-skills/sops-encryption/SKILL.md +124 -0
  456. package/bundled-skills/sre-dashboards/SKILL.md +143 -0
  457. package/bundled-skills/ssh-configuration/SKILL.md +324 -0
  458. package/bundled-skills/ssl-tls-management/SKILL.md +428 -0
  459. package/bundled-skills/ssl-tls-management/references/details.md +99 -0
  460. package/bundled-skills/startup-it-troubleshooting/SKILL.md +415 -0
  461. package/bundled-skills/supply-chain-attack-recon/SKILL.md +453 -0
  462. package/bundled-skills/supply-chain-attack-recon/references/details.md +258 -0
  463. package/bundled-skills/systemd-services/SKILL.md +379 -0
  464. package/bundled-skills/terraform-aws/SKILL.md +125 -0
  465. package/bundled-skills/terraform-azure/SKILL.md +415 -0
  466. package/bundled-skills/terraform-azure/references/details.md +231 -0
  467. package/bundled-skills/terraform-gcp/SKILL.md +369 -0
  468. package/bundled-skills/threat-modeling/SKILL.md +487 -0
  469. package/bundled-skills/user-management/SKILL.md +383 -0
  470. package/bundled-skills/using-agent-skills/SKILL.md +220 -0
  471. package/bundled-skills/vector-database-ops/SKILL.md +300 -0
  472. package/bundled-skills/vendor-management/SKILL.md +439 -0
  473. package/bundled-skills/vendor-management/references/details.md +109 -0
  474. package/bundled-skills/vercel-deployments/SKILL.md +296 -0
  475. package/bundled-skills/vllm-server/SKILL.md +236 -0
  476. package/bundled-skills/vmware-vcenter-attack/SKILL.md +412 -0
  477. package/bundled-skills/vpn-setup/SKILL.md +452 -0
  478. package/bundled-skills/vulnerability-scanning/SKILL.md +448 -0
  479. package/bundled-skills/waf-setup/SKILL.md +354 -0
  480. package/bundled-skills/waf-setup/references/details.md +211 -0
  481. package/bundled-skills/web2-recon/SKILL.md +440 -0
  482. package/bundled-skills/web2-recon/references/details.md +319 -0
  483. package/bundled-skills/web3-audit/SKILL.md +445 -0
  484. package/bundled-skills/web3-audit/references/details.md +224 -0
  485. package/bundled-skills/windows-hardening/SKILL.md +454 -0
  486. package/bundled-skills/windows-hardening/references/details.md +204 -0
  487. package/bundled-skills/windows-server/SKILL.md +318 -0
  488. package/bundled-skills/writing-guidelines/SKILL.md +60 -0
  489. package/bundled-skills/zero-trust/SKILL.md +461 -0
  490. package/package.json +1 -1
  491. package/skills_index.json +7874 -277
@@ -0,0 +1,740 @@
1
+ #!/usr/bin/env python3
2
+ from __future__ import annotations
3
+
4
+ import json
5
+ import os
6
+ import shutil
7
+ import subprocess
8
+ import sys
9
+ import tempfile
10
+ import zipfile
11
+ from pathlib import Path
12
+ from unittest.mock import patch
13
+
14
+
15
+ ROOT = Path(__file__).resolve().parents[1]
16
+ SKILLS = ROOT.parent
17
+ if (ROOT / "modules").exists():
18
+ SKILLS = ROOT / "modules"
19
+ COMPARE_FIXTURES = SKILLS / "fact-check-x-knowledge-compare" / "tests" / "fixtures"
20
+ AUTHORITY_FIXTURES = SKILLS / "fact-check-x-authoritative-verify" / "tests" / "fixtures"
21
+
22
+
23
+ def run(arguments: list[str], environment: dict[str, str] | None = None) -> dict:
24
+ process = subprocess.run(arguments, text=True, capture_output=True, check=False, env=environment)
25
+ if process.returncode:
26
+ raise AssertionError(process.stdout or process.stderr)
27
+ payload = json.loads([line for line in process.stdout.splitlines() if line.strip()][-1])
28
+ checkpoint = payload.get("checkpoint") or {}
29
+ acknowledgement = checkpoint.get("acknowledgement") or {}
30
+ if checkpoint.get("status") == "awaiting_user" and acknowledgement:
31
+ acknowledged = subprocess.run(
32
+ [sys.executable, str(ROOT / "scripts" / "fact_check_x.py"),
33
+ "acknowledge-stage", "--run-dir", str(Path(checkpoint["path"]).parent),
34
+ "--stage", checkpoint["stage"], "--token", acknowledgement["token"],
35
+ "--decision", "continue"],
36
+ text=True, capture_output=True, check=False, env=environment,
37
+ )
38
+ if acknowledged.returncode:
39
+ raise AssertionError(acknowledged.stdout or acknowledged.stderr)
40
+ return payload
41
+
42
+
43
+ def run_failed(arguments: list[str], environment: dict[str, str] | None = None) -> dict:
44
+ process = subprocess.run(arguments, text=True, capture_output=True, check=False, env=environment)
45
+ if process.returncode == 0:
46
+ raise AssertionError("命令应以非零状态结束")
47
+ return json.loads([line for line in process.stdout.splitlines() if line.strip()][-1])
48
+
49
+
50
+ def command(*arguments: str) -> list[str]:
51
+ return [sys.executable, str(ROOT / "scripts" / "fact_check_x.py"), *arguments]
52
+
53
+
54
+ def main() -> int:
55
+ with tempfile.TemporaryDirectory(prefix="fact-check-x-unified-") as temp:
56
+ sys.path.insert(0, str(ROOT / "scripts"))
57
+ import fact_check_x
58
+ from fact_check_x import (
59
+ collect_technical_notices,
60
+ merge_verification,
61
+ normalize_report_navigation,
62
+ )
63
+ assert fact_check_x.file_uri_for_path(
64
+ r"C:\WorkBuddy\fact-check-x\runs\sample run\02-comparison-report.html"
65
+ ) == "file:///C:/WorkBuddy/fact-check-x/runs/sample%20run/02-comparison-report.html"
66
+ assert fact_check_x.normalize_platform_path_text(
67
+ "/c/WorkBuddy/fact-check-x/runs/sample run/02-comparison-report.html",
68
+ "nt",
69
+ ) == "C:/WorkBuddy/fact-check-x/runs/sample run/02-comparison-report.html"
70
+ assert fact_check_x.file_uri_for_path(
71
+ "/c/WorkBuddy/fact-check-x/runs/sample run/02-comparison-report.html",
72
+ "nt",
73
+ ) == "file:///C:/WorkBuddy/fact-check-x/runs/sample%20run/02-comparison-report.html"
74
+
75
+ def assert_deliverable(item: dict, label: str, path: Path) -> None:
76
+ uri = path.resolve().as_uri()
77
+ assert item["label"] == label
78
+ assert item["path"] == str(path.resolve())
79
+ assert item["fileUri"] == uri
80
+ assert item["markdownLink"] == f"[打开{label}](<{uri}>)"
81
+
82
+ notice_run = Path(temp) / "technical-notice"
83
+ (notice_run / "capture").mkdir(parents=True)
84
+ (notice_run / "capture" / "results.json").write_text(
85
+ json.dumps({
86
+ "platforms": [{
87
+ "platform": "doubao",
88
+ "label": "豆包",
89
+ "references": [
90
+ {"sourceAcquisitionStatus": "blocked"},
91
+ {"contentAcquisition": "failed"},
92
+ ],
93
+ }],
94
+ }, ensure_ascii=False),
95
+ encoding="utf-8",
96
+ )
97
+ notices = collect_technical_notices(notice_run)
98
+ assert len(notices) == 1 and "豆包 2 条" in notices[0]
99
+ notice_html = normalize_report_navigation(
100
+ b"<html><head><style></style></head><body><main>test</main></body></html>",
101
+ "01-capture-report.html",
102
+ notices,
103
+ ).decode("utf-8")
104
+ assert 'data-fcx-run-notice="1"' in notice_html
105
+ assert "受影响且无法核验的主张按“疑似误导”呈现" in notice_html
106
+
107
+ merge_results = Path(temp) / "merge-results"
108
+ merge_results.mkdir()
109
+ (merge_results / "K1.json").write_text(json.dumps({
110
+ "schemaVersion": "fact-check-x/authority-result@1",
111
+ "requestId": "K1",
112
+ "searchMode": "trusted_search",
113
+ "requestCount": 1,
114
+ "authoritativeFinding": "直接问题权威结论。",
115
+ "claims": {
116
+ "doubao": {"covered": True, "claim": "直接问题平台主张。"},
117
+ },
118
+ "verdicts": {
119
+ "doubao": {"verdict": "contradicted"},
120
+ },
121
+ "evidenceGaps": [],
122
+ }), encoding="utf-8")
123
+ (merge_results / "K2.json").write_text(json.dumps({
124
+ "schemaVersion": "fact-check-x/authority-result@1",
125
+ "requestId": "K2",
126
+ "searchMode": "trusted_search",
127
+ "requestCount": 1,
128
+ "authoritativeFinding": "补充参考权威结论。",
129
+ "claims": {
130
+ "doubao": {"covered": True, "claim": "补充参考平台主张。"},
131
+ },
132
+ "verdicts": {
133
+ "doubao": {"verdict": "supported"},
134
+ },
135
+ "evidenceGaps": [],
136
+ }), encoding="utf-8")
137
+ merged = merge_verification({
138
+ "question": "测试",
139
+ "platforms": [{"platform": "doubao", "label": "豆包"}],
140
+ "knowledgePoints": [{
141
+ "id": "K1",
142
+ "description": "直接问题",
143
+ "role": "direct",
144
+ "trustedAnchor": {"eligible": False},
145
+ }, {
146
+ "id": "K2",
147
+ "description": "补充参考",
148
+ "role": "reference",
149
+ "trustedAnchor": {"eligible": False},
150
+ }],
151
+ "analysisGaps": [{
152
+ "stage": "comparison",
153
+ "knowledgePointId": "K1",
154
+ "platform": "doubao",
155
+ "reason": "原回答引用不足",
156
+ }],
157
+ }, merge_results)
158
+ assert merged["status"] == "completed"
159
+ assert merged["evidenceGaps"] == []
160
+ assert merged["finalAnswer"]["knowledgePointIds"] == ["K1"]
161
+ assert merged["supplementalFindings"]["knowledgePointIds"] == ["K2"]
162
+ assert merged["finalAnswer"]["answer"] == "直接问题权威结论。"
163
+ assert "补充参考权威结论" not in merged["finalAnswer"]["answer"]
164
+
165
+ run_dir = Path(temp) / "run"
166
+ results = COMPARE_FIXTURES / "results.json"
167
+ keyless_environment = {
168
+ **os.environ,
169
+ "TRUSTED_SEARCH_KEY": "",
170
+ "FACT_CHECK_X_TRUSTED_SEARCH_KEY_FILE": str(
171
+ Path(temp) / "missing-trusted-search-key"
172
+ ),
173
+ }
174
+ located = run(command("locate"))
175
+ assert set(located["skills"]) == {"collector", "comparison", "authority"}
176
+ capture_stage = run(command("prepare-comparison", "--results", str(results), "--run-dir", str(run_dir)))
177
+ assert capture_stage["stage"] == "capture_completed"
178
+ assert capture_stage["analysisExecution"]["mode"] == "single_pass"
179
+ assert capture_stage["analysisExecution"]["maxToolCallsAfterStageAcknowledgement"] == 3
180
+ assert len(capture_stage["analysisExecution"]["instructions"]) == 3
181
+ assert capture_stage["artifacts"]["answerReferenceReport"] == str((run_dir / "capture" / "report.html").resolve())
182
+ assert capture_stage["deliverables"][0]["path"] == str((run_dir / "01-capture-report.html").resolve())
183
+ assert_deliverable(
184
+ capture_stage["deliverables"][0],
185
+ "各方答案汇总",
186
+ run_dir / "01-capture-report.html",
187
+ )
188
+ assert capture_stage["checkpoint"]["mustPresentBeforeNextStage"] is True
189
+ assert capture_stage["checkpoint"]["path"] == str(
190
+ (run_dir / "01-capture-report.html").resolve()
191
+ )
192
+ assert "打开各方答案汇总" in capture_stage["checkpoint"]["message"]
193
+ assert (run_dir / "01-capture-report.html").exists()
194
+ assert len(capture_stage["platforms"]) == 2
195
+ comparison_stage = run(command("complete-comparison", "--results", str(results), "--analysis", str(COMPARE_FIXTURES / "comparison-analysis.json"), "--run-dir", str(run_dir)))
196
+ assert comparison_stage["stage"] == "comparison_completed"
197
+ assert comparison_stage["knowledgePointCount"] == 1
198
+ assert comparison_stage["artifacts"]["comparisonAnalysis"] == str(
199
+ (run_dir / "comparison-analysis.json").resolve()
200
+ )
201
+ assert (run_dir / "comparison-analysis.json").is_file()
202
+ assert comparison_stage["artifacts"]["comparisonReport"] == str((run_dir / "comparison.html").resolve())
203
+ assert comparison_stage["deliverables"][0]["path"] == str((run_dir / "02-comparison-report.html").resolve())
204
+ assert_deliverable(
205
+ comparison_stage["deliverables"][0],
206
+ "各方答案聚合(未核验)",
207
+ run_dir / "02-comparison-report.html",
208
+ )
209
+ assert comparison_stage["checkpoint"]["mustPresentBeforeNextStage"] is True
210
+ assert comparison_stage["checkpoint"]["path"] == str(
211
+ (run_dir / "02-comparison-report.html").resolve()
212
+ )
213
+ overwide_analysis = json.loads(
214
+ (COMPARE_FIXTURES / "comparison-analysis.json").read_text(encoding="utf-8")
215
+ )
216
+ overwide_analysis["knowledgePoints"][0]["claims"]["dknowc-chat"]["claim"] = (
217
+ "每人每月最高提取1400元,并另有最高300万元研发资助"
218
+ )
219
+ overwide_path = Path(temp) / "overwide-comparison-analysis.json"
220
+ overwide_path.write_text(
221
+ json.dumps(overwide_analysis, ensure_ascii=False), encoding="utf-8"
222
+ )
223
+ overwide_run = Path(temp) / "overwide-run"
224
+ run(command(
225
+ "prepare-comparison",
226
+ "--results", str(results),
227
+ "--run-dir", str(overwide_run),
228
+ ))
229
+ overwide_failure = run_failed(command(
230
+ "complete-comparison",
231
+ "--results", str(results),
232
+ "--analysis", str(overwide_path),
233
+ "--run-dir", str(overwide_run),
234
+ ))
235
+ assert "原子性门禁" in json.dumps(overwide_failure, ensure_ascii=False)
236
+ assert not (overwide_run / "comparison-gate.json").exists()
237
+ assert "打开各方答案聚合(未核验)" in comparison_stage["checkpoint"]["message"]
238
+ assert (run_dir / "02-comparison-report.html").exists()
239
+ prepared = run(command("prepare-authority", "--run-dir", str(run_dir)), keyless_environment)
240
+ assert prepared["taskCount"] == 1
241
+ assert prepared["status"] == "prepared" and prepared["trustedSearchRequiredCount"] == 0
242
+ request = json.loads((run_dir / "authority" / "requests" / "K1.json").read_text(encoding="utf-8"))
243
+ assert set(request["cloudPayload"]) == {"title", "knowledgePoint", "differingClaims"}
244
+ assert "answerMarkdown" not in json.dumps(request["cloudPayload"], ensure_ascii=False)
245
+ searched = run(command("search-authority", "--run-dir", str(run_dir), "--max-workers", "12"), keyless_environment)
246
+ assert searched["trustedSearchRequestCount"] == 0 and searched["dknowExemptCount"] == 1
247
+ assessments = run_dir / "authority" / "assessments"
248
+ assessments.mkdir(parents=True)
249
+ assessment = json.loads((AUTHORITY_FIXTURES / "K1-assessment.json").read_text(encoding="utf-8"))
250
+ (assessments / "K1.json").write_text(json.dumps(assessment, ensure_ascii=False), encoding="utf-8")
251
+ original_pipeline_run = fact_check_x.run
252
+
253
+ def fail_authority_report(arguments, environment=None):
254
+ if any(Path(str(item)).name == "render_authority_report.py" for item in arguments):
255
+ raise fact_check_x.PipelineError("强制报告渲染失败")
256
+ return original_pipeline_run(arguments, environment)
257
+
258
+ with patch.object(fact_check_x, "run", side_effect=fail_authority_report):
259
+ try:
260
+ fact_check_x.finalize_authority(
261
+ type("Args", (), {"run_dir": str(run_dir), "assessments_dir": None})(),
262
+ {key: Path(value) for key, value in located["skills"].items()},
263
+ )
264
+ except fact_check_x.PipelineError as exc:
265
+ assert "强制报告渲染失败" in str(exc)
266
+ else:
267
+ raise AssertionError("报告渲染失败应回滚权威核验事务")
268
+ assert json.loads(
269
+ (run_dir / "authority-gate.json").read_text(encoding="utf-8")
270
+ )["status"] == "searched"
271
+ assert not list((run_dir / "authority" / "results").glob("*.json"))
272
+ assert not (run_dir / "verification.json").exists()
273
+ assert not (run_dir / "03-authority-report.html").exists()
274
+ finalized = run(command("finalize-authority", "--run-dir", str(run_dir)))
275
+ assert finalized["status"] == "completed"
276
+ assert finalized["stage"] == "authority_completed"
277
+ assert finalized["deliverables"][0]["path"] == str(
278
+ (run_dir / "03-authority-report.html").resolve()
279
+ )
280
+ assert_deliverable(
281
+ finalized["deliverables"][0],
282
+ "权威核验后的最终答案",
283
+ run_dir / "03-authority-report.html",
284
+ )
285
+ assert finalized["checkpoint"]["mustPresentBeforeNextStage"] is True
286
+ assert finalized["checkpoint"]["path"] == str(
287
+ (run_dir / "03-authority-report.html").resolve()
288
+ )
289
+ assert "打开权威核验后的最终答案" in finalized["checkpoint"]["message"]
290
+ assert (run_dir / "03-authority-report.html").exists()
291
+ assert json.loads((run_dir / "authority-gate.json").read_text(encoding="utf-8"))["status"] == "finalized"
292
+ reopened = run(command(
293
+ "reopen-authority",
294
+ "--run-dir", str(run_dir),
295
+ "--reason", "修正被截断的权威结论",
296
+ ))
297
+ assert reopened["stage"] == "authority_reopened"
298
+ assert reopened["revision"] == 1
299
+ revision_dir = run_dir / "authority" / "revisions" / "revision-001"
300
+ assert (revision_dir / "revision.json").is_file()
301
+ assert (revision_dir / "verification.json").is_file()
302
+ assert (revision_dir / "authority" / "results" / "K1.json").is_file()
303
+ assert not list((run_dir / "authority" / "results").glob("*.json"))
304
+ assert not (run_dir / "verification.json").exists()
305
+ assert not (run_dir / "03-authority-report.html").exists()
306
+ reopened_gate = json.loads((run_dir / "authority-gate.json").read_text(encoding="utf-8"))
307
+ assert reopened_gate["status"] == "searched"
308
+ comparison_data = json.loads((run_dir / "comparison.json").read_text(encoding="utf-8"))
309
+ exact_title = comparison_data["knowledgePoints"][0]["description"]
310
+ assessment["authoritativeFinding"] = f"{exact_title}:每人每月最高提取1400元。"
311
+ (assessments / "K1.json").write_text(
312
+ json.dumps(assessment, ensure_ascii=False), encoding="utf-8"
313
+ )
314
+ refinalized = run(command("finalize-authority", "--run-dir", str(run_dir)))
315
+ assert refinalized["status"] == "completed"
316
+ reopened_verification = json.loads(
317
+ (run_dir / "verification.json").read_text(encoding="utf-8")
318
+ )
319
+ assert reopened_verification["finalAnswer"]["items"][0]["answer"] == assessment["authoritativeFinding"]
320
+ locked_verification = (run_dir / "verification.json").read_bytes()
321
+ locked_authority_report = (run_dir / "03-authority-report.html").read_bytes()
322
+ (run_dir / "verification.json").write_bytes(locked_verification + b"\n")
323
+ immutable_rejection = run_failed(command(
324
+ "deliver", "--results", str(results), "--run-dir", str(run_dir)
325
+ ))
326
+ assert "第三步权威核验结果已被修改" in immutable_rejection["error"]
327
+ (run_dir / "verification.json").write_bytes(locked_verification)
328
+ delivered = run(command("deliver", "--results", str(results), "--run-dir", str(run_dir)))
329
+ assert delivered["status"] == "completed"
330
+ assert delivered["trustedSearchRequestCount"] == 0 and delivered["dknowExemptCount"] == 1
331
+ assert delivered["answerReferenceReport"] == str((run_dir / "capture" / "report.html").resolve())
332
+ assert delivered["comparisonReport"] == str((run_dir / "comparison.html").resolve())
333
+ assert delivered["artifacts"]["report"] == str((run_dir / "report.html").resolve())
334
+ deliverable_paths = [item["path"] for item in delivered["deliverables"]]
335
+ assert deliverable_paths[:4] == [
336
+ str((run_dir / "01-capture-report.html").resolve()),
337
+ str((run_dir / "02-comparison-report.html").resolve()),
338
+ str((run_dir / "03-authority-report.html").resolve()),
339
+ str((run_dir / "04-final-report.html").resolve()),
340
+ ]
341
+ assert deliverable_paths[4] == delivered["artifacts"]["reportPackage"]
342
+ with zipfile.ZipFile(deliverable_paths[4]) as report_archive:
343
+ packaged_checkpoints = json.loads(
344
+ report_archive.read(
345
+ "fact-check-x-report/data/stage-checkpoints.json"
346
+ ).decode("utf-8")
347
+ )
348
+ assert list(packaged_checkpoints["stages"]) == [
349
+ "capture", "comparison", "authority", "evaluation"
350
+ ]
351
+ assert packaged_checkpoints["stages"]["evaluation"]["status"] == "completed"
352
+ for packaged_stage in packaged_checkpoints["stages"].values():
353
+ for packaged_item in packaged_stage.get("deliverables") or []:
354
+ assert packaged_item["fileUri"].startswith("../")
355
+ assert "file://" not in packaged_item["markdownLink"]
356
+ assert "file://" not in packaged_item["message"]
357
+ assert delivered["checkpoint"]["mustPresentBeforeNextStage"] is True
358
+ assert delivered["checkpoint"]["path"] == str(
359
+ (run_dir / "04-final-report.html").resolve()
360
+ )
361
+ assert "打开各方答案测评报告" in delivered["checkpoint"]["message"]
362
+ assert (run_dir / "verification.json").read_bytes() == locked_verification
363
+ assert (run_dir / "03-authority-report.html").read_bytes() == locked_authority_report
364
+ assert all(Path(item["path"]).exists() for item in delivered["deliverables"])
365
+ for item, label, path in (
366
+ (delivered["deliverables"][0], "各方答案汇总", run_dir / "01-capture-report.html"),
367
+ (delivered["deliverables"][1], "各方答案聚合(未核验)", run_dir / "02-comparison-report.html"),
368
+ (delivered["deliverables"][2], "权威核验后的最终答案", run_dir / "03-authority-report.html"),
369
+ (delivered["deliverables"][3], "各方答案测评报告", run_dir / "04-final-report.html"),
370
+ (delivered["deliverables"][4], "完整可分发报告包", Path(deliverable_paths[4])),
371
+ ):
372
+ assert_deliverable(item, label, path)
373
+ manifest = json.loads((run_dir / "pipeline.json").read_text(encoding="utf-8"))
374
+ verification = json.loads((run_dir / "verification.json").read_text(encoding="utf-8"))
375
+ report = (run_dir / "report.html").read_text(encoding="utf-8")
376
+ authority_report = (run_dir / "03-authority-report.html").read_text(
377
+ encoding="utf-8"
378
+ )
379
+ comparison_deliverable = (run_dir / "02-comparison-report.html").read_text(
380
+ encoding="utf-8"
381
+ )
382
+ assert manifest["schemaVersion"] == "fact-check-x/pipeline@2"
383
+ assert verification["finalAnswer"]["status"] == "verified"
384
+ assert verification["finalAnswer"]["knowledgePointIds"] == ["K1"]
385
+ assert verification["knowledgePoints"][0]["authority"]["verdicts"]["doubao"]["category"] == "misleading"
386
+ assert "权威核验报告(问题:" in authority_report
387
+ assert "权威核验后的最终答案" in authority_report
388
+ assert "各平台裁决" not in authority_report
389
+ assert "data-fcx-authority-binding-sha256" not in authority_report
390
+ report_names = [
391
+ "01-capture-report.html",
392
+ "02-comparison-report.html",
393
+ "03-authority-report.html",
394
+ "04-final-report.html",
395
+ ]
396
+ for report_name in report_names:
397
+ report_html = (run_dir / report_name).read_text(encoding="utf-8")
398
+ assert report_html.count('data-fcx-report-nav="1"') == 1
399
+ assert 'aria-current="page"' in report_html
400
+ assert "来源链接待补" not in report_html
401
+ assert all(
402
+ f'href="{target}"' in report_html
403
+ for target in report_names
404
+ if target != report_name
405
+ )
406
+ assert all(
407
+ f'href="{target}"' in comparison_deliverable
408
+ for target in (
409
+ "01-capture-report.html",
410
+ "03-authority-report.html",
411
+ "04-final-report.html",
412
+ )
413
+ )
414
+ assert "① 平台表现概览" in report
415
+ assert "② 逐知识点核验明细" in report
416
+ assert "③ 原始答案与参考文献(存证)" in report
417
+ assert "④ 指标口径速查" in report
418
+ assert "⑤ 评测元信息" in report
419
+ assert report.count("② 逐知识点核验明细") == 1
420
+ assert 'data-fcx-locked-role="direct"' in report
421
+ assert 'data-fcx-locked-role="reference"' in report
422
+ assert "② 直接答案逐知识点测评" not in report
423
+ assert "③ 补充参考逐知识点测评" not in report
424
+ assert "② 直接答案逐条判定" not in report
425
+ assert "②-补 补充参考分析" not in report
426
+ assert (run_dir / "comparison.html").exists()
427
+ capture_report = (run_dir / "capture" / "report.html").read_text(encoding="utf-8")
428
+ assert "各方答案汇总(问题:" in capture_report
429
+ assert "每人每月最高提取 1400 元" in capture_report
430
+ assert (run_dir / "capture" / "report.md").exists()
431
+ assert manifest["artifacts"]["answerReferenceReport"] == str((run_dir / "capture" / "report.html").resolve())
432
+ assert manifest["artifacts"]["captureGate"] == str((run_dir / "capture-gate.json").resolve())
433
+ assert manifest["artifacts"]["comparisonAnalysis"] == str(
434
+ (run_dir / "comparison-analysis.json").resolve()
435
+ )
436
+ assert manifest["artifacts"]["authorityGate"] == str((run_dir / "authority-gate.json").resolve())
437
+
438
+ artifact_source = Path(temp) / "artifact-source"
439
+ artifact_source.mkdir()
440
+ artifact_results = json.loads(results.read_text(encoding="utf-8"))
441
+ for platform in artifact_results["platforms"]:
442
+ platform_id = platform["platform"]
443
+ platform["artifacts"] = {
444
+ "screenshot": f"artifacts/{platform_id}/screenshot.png",
445
+ "html": f"artifacts/{platform_id}/page.html",
446
+ }
447
+ artifact_dir = artifact_source / "artifacts" / platform_id
448
+ artifact_dir.mkdir(parents=True)
449
+ (artifact_dir / "screenshot.png").write_bytes(f"png:{platform_id}".encode())
450
+ (artifact_dir / "page.html").write_text(
451
+ f"<html>{platform_id}</html>", encoding="utf-8"
452
+ )
453
+ artifact_results_path = artifact_source / "results.json"
454
+ artifact_results_path.write_text(
455
+ json.dumps(artifact_results, ensure_ascii=False), encoding="utf-8"
456
+ )
457
+ (artifact_source / "capture-recovery.json").write_text(
458
+ json.dumps({
459
+ "schemaVersion": "fact-check-x/capture-recovery@2",
460
+ "status": "completed",
461
+ }, ensure_ascii=False),
462
+ encoding="utf-8",
463
+ )
464
+ artifact_run = Path(temp) / "artifact-run"
465
+ run(command(
466
+ "prepare-comparison",
467
+ "--results",
468
+ str(artifact_results_path),
469
+ "--run-dir",
470
+ str(artifact_run),
471
+ ))
472
+ artifact_gate = json.loads(
473
+ (artifact_run / "capture-gate.json").read_text(encoding="utf-8")
474
+ )
475
+ assert len(artifact_gate["artifactSha256"]) == 4
476
+ assert artifact_gate["recoverySha256"]
477
+ assert (artifact_run / "capture/capture-recovery.json").is_file()
478
+ for platform in artifact_results["platforms"]:
479
+ platform_id = platform["platform"]
480
+ assert (
481
+ artifact_run / f"capture/artifacts/{platform_id}/screenshot.png"
482
+ ).is_file()
483
+ assert (
484
+ artifact_run / f"capture/artifacts/{platform_id}/page.html"
485
+ ).is_file()
486
+ assert (
487
+ artifact_run / f"artifacts/{platform_id}/screenshot.png"
488
+ ).is_file()
489
+ assert (
490
+ artifact_run / f"artifacts/{platform_id}/page.html"
491
+ ).is_file()
492
+ missing_artifact_results = json.loads(
493
+ artifact_results_path.read_text(encoding="utf-8")
494
+ )
495
+ (
496
+ artifact_source
497
+ / missing_artifact_results["platforms"][0]["artifacts"]["screenshot"]
498
+ ).unlink()
499
+ missing_artifact_run = Path(temp) / "missing-artifact-run"
500
+ missing_artifact = run_failed(command(
501
+ "prepare-comparison",
502
+ "--results",
503
+ str(artifact_results_path),
504
+ "--run-dir",
505
+ str(missing_artifact_run),
506
+ ))
507
+ assert "存证文件不存在" in missing_artifact["error"]
508
+
509
+ configuration_run = Path(temp) / "configuration-run"
510
+ run(command("prepare-comparison", "--results", str(results), "--run-dir", str(configuration_run)))
511
+ configuration_analysis = json.loads((COMPARE_FIXTURES / "comparison-analysis.json").read_text(encoding="utf-8"))
512
+ configuration_analysis["knowledgePoints"][0]["trustedAnchor"] = {"eligible": False}
513
+ configuration_analysis["knowledgePoints"][0]["claims"]["dknowc-chat"] = {
514
+ "covered": False,
515
+ "claim": "",
516
+ "answerExcerpt": "",
517
+ "citedReferenceIndexes": [],
518
+ "answerLevelReferenceIndexes": [],
519
+ "faithfulness": "insufficient",
520
+ "reason": "",
521
+ "evidence": [],
522
+ }
523
+ configuration_analysis_path = configuration_run / "comparison-analysis.json"
524
+ configuration_analysis_path.write_text(json.dumps(configuration_analysis, ensure_ascii=False), encoding="utf-8")
525
+ run(command("complete-comparison", "--results", str(results), "--analysis", str(configuration_analysis_path), "--run-dir", str(configuration_run)))
526
+ configuration_required = run_failed(command(
527
+ "prepare-authority",
528
+ "--run-dir",
529
+ str(configuration_run),
530
+ ), keyless_environment)
531
+ assert configuration_required["status"] == "configuration_required"
532
+ assert configuration_required["action"] == "configure_trusted_search"
533
+ assert configuration_required["trustedSearchRequiredCount"] == 1
534
+ assert "您只需完成登录" in configuration_required["userPrompt"]
535
+ assert "自动读取已有的可用 Key" in configuration_required["userPrompt"]
536
+ assert configuration_required["configuration"]["providerUrl"] == "https://platform.dknowc.cn/auth/#/login"
537
+ assert configuration_required["configuration"]["interaction"] == "browser_login_only"
538
+ assert configuration_required["configuration"]["requiresChatSecret"] is False
539
+ assert configuration_required["configuration"]["autoResume"] is True
540
+ assert configuration_required["configuration"]["sharedAcrossCarriers"] is True
541
+ assert configuration_required["configuration"]["command"][-1] == "configure"
542
+ assert configuration_required["configuration"]["command"][-2].endswith(
543
+ "trusted_search_config.py"
544
+ )
545
+ assert json.loads((configuration_run / "authority-gate.json").read_text(encoding="utf-8"))["status"] == "configuration_required"
546
+ search_blocked = run_failed(command(
547
+ "search-authority",
548
+ "--run-dir",
549
+ str(configuration_run),
550
+ "--max-workers",
551
+ "12",
552
+ ), keyless_environment)
553
+ assert search_blocked["status"] == "configuration_required"
554
+ assert search_blocked["action"] == "configure_trusted_search"
555
+ assert not (configuration_run / "authority" / "evidence" / "batch.json").exists()
556
+ bypass_attempt = run_failed(command(
557
+ "finalize-authority",
558
+ "--run-dir",
559
+ str(configuration_run),
560
+ ), keyless_environment)
561
+ assert bypass_attempt["status"] == "failed"
562
+ assert "禁止写入裁决" in bypass_attempt["error"]
563
+ bypass_delivery = run_failed(command(
564
+ "deliver",
565
+ "--results",
566
+ str(results),
567
+ "--run-dir",
568
+ str(configuration_run),
569
+ ), keyless_environment)
570
+ assert bypass_delivery["status"] == "failed"
571
+ assert "缺少 authority 阶段产物交付记录" in bypass_delivery["error"]
572
+
573
+ tamper_run = Path(temp) / "tamper-run"
574
+ run(command("prepare-comparison", "--results", str(results), "--run-dir", str(tamper_run)))
575
+ run(command("complete-comparison", "--results", str(results), "--analysis", str(COMPARE_FIXTURES / "comparison-analysis.json"), "--run-dir", str(tamper_run)))
576
+ tampered = json.loads((tamper_run / "comparison.json").read_text(encoding="utf-8"))
577
+ tampered["knowledgePoints"][0]["claims"]["doubao"]["sourceLevel"] = "official"
578
+ (tamper_run / "comparison.json").write_text(json.dumps(tampered, ensure_ascii=False), encoding="utf-8")
579
+ tamper_rejected = run_failed(command("prepare-authority", "--run-dir", str(tamper_run)))
580
+ assert "被修改" in tamper_rejected["error"]
581
+
582
+ pollution_run = Path(temp) / "pollution-run"
583
+ run(command("prepare-comparison", "--results", str(results), "--run-dir", str(pollution_run)))
584
+ run(command("complete-comparison", "--results", str(results), "--analysis", str(COMPARE_FIXTURES / "comparison-analysis.json"), "--run-dir", str(pollution_run)))
585
+ run(command("prepare-authority", "--run-dir", str(pollution_run)))
586
+ run(command("search-authority", "--run-dir", str(pollution_run), "--max-workers", "12"))
587
+ pollution_assessments = pollution_run / "authority" / "assessments"
588
+ pollution_assessments.mkdir(parents=True)
589
+ shutil.copyfile(AUTHORITY_FIXTURES / "K1-assessment.json", pollution_assessments / "K1.json")
590
+ pollution_results = pollution_run / "authority" / "results"
591
+ pollution_results.mkdir(parents=True)
592
+ (pollution_results / "KP-001.json").write_text("{}\n", encoding="utf-8")
593
+ pollution_rejected = run_failed(command("finalize-authority", "--run-dir", str(pollution_run)))
594
+ assert "results 目录必须为空" in pollution_rejected["error"]
595
+
596
+ invalid_assessments = Path(temp) / "invalid-assessments"
597
+ invalid_assessments.mkdir()
598
+ (invalid_assessments / "K1.json").write_text(json.dumps({
599
+ "requestId": "K1",
600
+ "verdict": "supported",
601
+ "officialAnswer": "旧结构结论",
602
+ "platformAssessment": {
603
+ "dknowc-chat": {"verdict": "supported", "reason": "旧结构"},
604
+ "doubao": {"verdict": "supported", "reason": "旧结构"},
605
+ },
606
+ }, ensure_ascii=False), encoding="utf-8")
607
+ invalid_run = Path(temp) / "invalid-run"
608
+ run(command("prepare-comparison", "--results", str(results), "--run-dir", str(invalid_run)))
609
+ run(command("complete-comparison", "--results", str(results), "--analysis", str(COMPARE_FIXTURES / "comparison-analysis.json"), "--run-dir", str(invalid_run)))
610
+ run(command("prepare-authority", "--run-dir", str(invalid_run)))
611
+ run(command("search-authority", "--run-dir", str(invalid_run), "--max-workers", "12"))
612
+ invalid_final = run_failed(command(
613
+ "finalize-authority",
614
+ "--run-dir",
615
+ str(invalid_run),
616
+ "--assessments-dir",
617
+ str(invalid_assessments),
618
+ ))
619
+ assert invalid_final["status"] == "failed"
620
+ assert "裁决文件结构错误" in invalid_final["error"]
621
+ assert not (invalid_run / "authority" / "results" / "K1.json").exists()
622
+
623
+ review_run = Path(temp) / "review-run"
624
+ run(command("prepare-comparison", "--results", str(results), "--run-dir", str(review_run)))
625
+ run(command("complete-comparison", "--results", str(results), "--analysis", str(COMPARE_FIXTURES / "comparison-analysis.json"), "--run-dir", str(review_run)))
626
+ run(command("prepare-authority", "--run-dir", str(review_run)))
627
+ run(command("search-authority", "--run-dir", str(review_run), "--max-workers", "12"))
628
+ review_assessments = review_run / "authority" / "assessments"
629
+ review_assessments.mkdir(parents=True)
630
+ review_assessment = json.loads((AUTHORITY_FIXTURES / "K1-assessment.json").read_text(encoding="utf-8"))
631
+ review_assessment["verdicts"]["doubao"] = {
632
+ "verdict": "insufficient",
633
+ "reason": "当前证据不足以完成裁决",
634
+ "evidenceIds": [],
635
+ }
636
+ (review_assessments / "K1.json").write_text(json.dumps(review_assessment, ensure_ascii=False), encoding="utf-8")
637
+ review_final = run(command("finalize-authority", "--run-dir", str(review_run)))
638
+ assert review_final["status"] == "completed"
639
+ assert review_final["stage"] == "authority_completed"
640
+ assert review_final["evidenceGapCount"] == 1
641
+ assert review_final["deliverables"][0]["path"] == str(
642
+ (review_run / "03-authority-report.html").resolve()
643
+ )
644
+ review_authority_report = (
645
+ review_run / "03-authority-report.html"
646
+ ).read_text(encoding="utf-8")
647
+ assert "证据不足项" in review_authority_report
648
+ assert 'href="04-final-report.html"' in review_authority_report
649
+ assert json.loads((review_run / "authority-gate.json").read_text(encoding="utf-8"))["status"] == "finalized"
650
+ review_delivery = run(command("deliver", "--results", str(results), "--run-dir", str(review_run)))
651
+ assert review_delivery["status"] == "completed"
652
+ assert review_delivery["evidenceGapCount"] == 1
653
+ assert (review_run / "04-final-report.html").is_file()
654
+ review_verification = json.loads(
655
+ (review_run / "verification.json").read_text(encoding="utf-8")
656
+ )
657
+ assert review_verification["status"] == "completed"
658
+ assert review_verification["evidenceGapCount"] == 1
659
+ assert review_verification["evidenceGaps"][0]["platform"] == "doubao"
660
+
661
+ failed_results = json.loads(results.read_text(encoding="utf-8"))
662
+ failed_results["platforms"][0]["answerMarkdown"] = "为您智能匹配到当前所在区域为“北京市”,如想咨询其他区域可点击修改"
663
+ failed_results["platforms"][1]["status"] = "failed"
664
+ failed_results["platforms"][1]["answerMarkdown"] = ""
665
+ failed_results["platforms"][1]["error"] = "No answer text detected."
666
+ failed_path = Path(temp) / "failed-results.json"
667
+ failed_path.write_text(json.dumps(failed_results, ensure_ascii=False), encoding="utf-8")
668
+ failed_run = Path(temp) / "failed-run"
669
+ rejected = run_failed(command("prepare-comparison", "--results", str(failed_path), "--run-dir", str(failed_run)))
670
+ assert rejected["status"] == "failed"
671
+ assert "禁止进入知识点对比" in rejected["error"]
672
+ assert not (failed_run / "comparison-task.json").exists()
673
+
674
+ answered_with_region_footer = json.loads(results.read_text(encoding="utf-8"))
675
+ answered_with_region_footer["platforms"][0]["answerMarkdown"] = (
676
+ "北京市高考报名资格、网上申请、填报缴费和现场确认的完整政策回答。" * 10
677
+ + "页面底部:为您智能匹配到当前所在区域为“北京市”,如想咨询其他区域可点击修改"
678
+ )
679
+ answered_with_region_footer_path = Path(temp) / "answered-with-region-footer.json"
680
+ answered_with_region_footer_path.write_text(
681
+ json.dumps(answered_with_region_footer, ensure_ascii=False),
682
+ encoding="utf-8",
683
+ )
684
+ answered_with_region_footer_run = Path(temp) / "answered-with-region-footer-run"
685
+ accepted_with_footer = run(command(
686
+ "prepare-comparison",
687
+ "--results",
688
+ str(answered_with_region_footer_path),
689
+ "--run-dir",
690
+ str(answered_with_region_footer_run),
691
+ ))
692
+ assert accepted_with_footer["stage"] == "capture_completed"
693
+ assert (answered_with_region_footer_run / "comparison-task.json").exists()
694
+
695
+ recovery_capture = Path(temp) / "recovery-capture"
696
+ recovery_capture.mkdir()
697
+ recovery_results = recovery_capture / "results.json"
698
+ recovery_results.write_text(results.read_text(encoding="utf-8"), encoding="utf-8")
699
+ (recovery_capture / "capture-recovery.json").write_text(
700
+ json.dumps({
701
+ "schemaVersion": "fact-check-x/capture-recovery@2",
702
+ "status": "required",
703
+ "action": "computer_use",
704
+ }, ensure_ascii=False),
705
+ encoding="utf-8",
706
+ )
707
+ recovery_run = Path(temp) / "recovery-run"
708
+ recovery_rejected = run_failed(command(
709
+ "prepare-comparison",
710
+ "--results",
711
+ str(recovery_results),
712
+ "--run-dir",
713
+ str(recovery_run),
714
+ ))
715
+ assert "Computer Use" in recovery_rejected["error"]
716
+ assert not (recovery_run / "comparison-task.json").exists()
717
+ assert not (ROOT / "assets").exists()
718
+ if os.getenv("FACT_CHECK_X_ASSERTIONS_OUTPUT"):
719
+ Path(os.environ["FACT_CHECK_X_ASSERTIONS_OUTPUT"]).write_text(json.dumps({
720
+ "schemaVersion": "fact-check-x/test-assertions@1",
721
+ "actualAssertionIds": [
722
+ "report.stage_artifacts_visible",
723
+ "report.checkpoints_indexed",
724
+ "report.unverified_draft_visible",
725
+ "report.verified_final_answer_visible",
726
+ "report.stage2_role_sections",
727
+ "report.stage4_single_locked_detail",
728
+ "report.technical_failure_notice",
729
+ "report.renamed_four_stages",
730
+ "authority.finalize_transaction_rollback",
731
+ "comparison.overwide_claim_blocks_authority",
732
+ "path.windows_drive_normalized",
733
+ ],
734
+ }), encoding="utf-8")
735
+ print("PASS Fact-Check-X 统一入口")
736
+ return 0
737
+
738
+
739
+ if __name__ == "__main__":
740
+ raise SystemExit(main())