noteconnection 1.7.0 → 1.9.0

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 (328) hide show
  1. package/LICENSE +674 -21
  2. package/README.md +260 -1626
  3. package/dist/src/agent_workspace.contract.parity.test.js +159 -0
  4. package/dist/src/agent_workspace.frontend.test.js +10388 -0
  5. package/dist/src/agent_workspace.locale.contract.test.js +95 -0
  6. package/dist/src/agent_workspace.runtime.behavior.test.js +5072 -0
  7. package/dist/src/android.knowledgebase.picker.contract.test.js +102 -0
  8. package/dist/src/appimage.patchelf.test.js +113 -0
  9. package/dist/src/appimage.portability.test.js +156 -0
  10. package/dist/src/backend/FileLoader.js +18 -4
  11. package/dist/src/backend/FileLoader.test.js +125 -0
  12. package/dist/src/backend/GraphBuilder.identity.test.js +86 -0
  13. package/dist/src/backend/GraphBuilder.js +66 -18
  14. package/dist/src/backend/GraphBuilder.matching.test.js +127 -0
  15. package/dist/src/backend/GraphMetrics.js +0 -3
  16. package/dist/src/backend/ResourceIdentity.js +155 -0
  17. package/dist/src/backend/ResourceIdentity.test.js +113 -0
  18. package/dist/src/backend/algorithms/CycleDetection.js +0 -1
  19. package/dist/src/backend/algorithms/HybridEngine.js +0 -3
  20. package/dist/src/backend/algorithms/LayoutEngine.js +0 -1
  21. package/dist/src/backend/algorithms/StatisticalAnalyzer.js +0 -4
  22. package/dist/src/backend/algorithms/TopologicalSort.js +0 -2
  23. package/dist/src/backend/build_dag.js +0 -1
  24. package/dist/src/capacitor.bridge.serialization.contract.test.js +3 -0
  25. package/dist/src/capacitor.runtime.contract.test.js +11 -2
  26. package/dist/src/copy.assets.contract.test.js +130 -0
  27. package/dist/src/core/Graph.js +138 -42
  28. package/dist/src/core/Graph.test.js +74 -0
  29. package/dist/src/core/NoteConnection.js +2 -2
  30. package/dist/src/core/PathBridge.js +293 -5
  31. package/dist/src/core/ResourceReference.js +17 -0
  32. package/dist/src/desktop.godot.pack.test.js +142 -0
  33. package/dist/src/desktop.runtime.graph.test.js +66 -0
  34. package/dist/src/export/WorkspaceExportBundle.js +1174 -0
  35. package/dist/src/export/WorkspaceExportBundle.test.js +1541 -0
  36. package/dist/src/export/index.js +18 -0
  37. package/dist/src/export/types.js +2 -0
  38. package/dist/src/fixrisk.issue.verifier.contract.test.js +3 -1
  39. package/dist/src/foundation.ann.runtime.contract.test.js +81 -0
  40. package/dist/src/foundation.release.evidence.contract.test.js +524 -0
  41. package/dist/src/foundation.sqlite.runtime.contract.test.js +88 -0
  42. package/dist/src/frontend/README.md +260 -1626
  43. package/dist/src/frontend/agent_workspace.js +6011 -0
  44. package/dist/src/frontend/agent_workspace_runtime.js +4434 -0
  45. package/dist/src/frontend/analysis.js +31 -4
  46. package/dist/src/frontend/app.js +2178 -62
  47. package/dist/src/frontend/focus_mode_interactions.js +33 -0
  48. package/dist/src/frontend/godot_future_path_renderer.js +540 -0
  49. package/dist/src/frontend/godot_tree_interactions.js +178 -0
  50. package/dist/src/frontend/graph_state.mjs +105 -0
  51. package/dist/src/frontend/hosted_future_path_runtime.js +157 -0
  52. package/dist/src/frontend/i18n.mjs +186 -0
  53. package/dist/src/frontend/index.html +672 -268
  54. package/dist/src/frontend/knowledge_projection_contract.js +230 -0
  55. package/dist/src/frontend/knowledge_projection_store.js +214 -0
  56. package/dist/src/frontend/layout_gpu.js +12 -4
  57. package/dist/src/frontend/libs/path_core.js +158 -42
  58. package/dist/src/frontend/locales/en.json +753 -5
  59. package/dist/src/frontend/locales/zh.json +753 -5
  60. package/dist/src/frontend/main.mjs +60 -0
  61. package/dist/src/frontend/markdown_runtime.js +827 -0
  62. package/dist/src/frontend/mobile_budget_runtime.js +33 -0
  63. package/dist/src/frontend/mobile_exact_analyzer.js +393 -0
  64. package/dist/src/frontend/mobile_identity_contract.js +221 -0
  65. package/dist/src/frontend/mobile_semantic_comparator.js +264 -0
  66. package/dist/src/frontend/notemd.css +49 -0
  67. package/dist/src/frontend/notemd.html +7 -1
  68. package/dist/src/frontend/notemd.js +64 -0
  69. package/dist/src/frontend/path.html +113 -2
  70. package/dist/src/frontend/path_app.js +2108 -130
  71. package/dist/src/frontend/path_layout.mjs +143 -0
  72. package/dist/src/frontend/path_mermaid_utils.mjs +108 -0
  73. package/dist/src/frontend/path_modules_bridge.js +486 -0
  74. package/dist/src/frontend/path_state.mjs +118 -0
  75. package/dist/src/frontend/path_styles.css +146 -0
  76. package/dist/src/frontend/path_worker_bridge.mjs +85 -0
  77. package/dist/src/frontend/reader.js +393 -33
  78. package/dist/src/frontend/runtime_bridge.js +67 -54
  79. package/dist/src/frontend/runtime_bridge.mjs +279 -0
  80. package/dist/src/frontend/settings.js +130 -12
  81. package/dist/src/frontend/simulationWorker.js +1 -1
  82. package/dist/src/frontend/source_manager.js +297 -22
  83. package/dist/src/frontend/storage_provider.js +661 -71
  84. package/dist/src/frontend/styles.css +2814 -72
  85. package/dist/src/frontend/workbench_state.mjs +101 -0
  86. package/dist/src/frontend/workspace_panes.js +10272 -0
  87. package/dist/src/frontend.locale.contract.test.js +62 -0
  88. package/dist/src/frontend.runtime.assets.contract.test.js +81 -0
  89. package/dist/src/godot.sidecar.bootstrap.contract.test.js +244 -0
  90. package/dist/src/graph.answer.operator.contract.test.js +72 -0
  91. package/dist/src/index.js +6 -2
  92. package/dist/src/index.knowledge-root.test.js +118 -0
  93. package/dist/src/indexing/IndexLifecycle.js +217 -0
  94. package/dist/src/indexing/IndexLifecycle.test.js +73 -0
  95. package/dist/src/indexing/SegmentBuilder.js +64 -0
  96. package/dist/src/indexing/UnitBuilder.js +48 -0
  97. package/dist/src/indexing/types.js +2 -0
  98. package/dist/src/knowledge.api.contract.test.js +172 -0
  99. package/dist/src/knowledge_projection.contract.test.js +134 -0
  100. package/dist/src/knowledge_projection_store.test.js +200 -0
  101. package/dist/src/learning/AnswerQualityEvaluation.js +153 -0
  102. package/dist/src/learning/AnswerQualityEvaluation.test.js +118 -0
  103. package/dist/src/learning/KnowledgeLearningPlatform.js +11181 -0
  104. package/dist/src/learning/KnowledgeLearningPlatform.persistence.test.js +745 -0
  105. package/dist/src/learning/KnowledgeLearningPlatform.program-f.test.js +99 -0
  106. package/dist/src/learning/KnowledgeLearningPlatform.test.js +3208 -0
  107. package/dist/src/learning/KnowledgeWorkspaceConversationRegression.js +2998 -0
  108. package/dist/src/learning/KnowledgeWorkspaceConversationRegression.test.js +3936 -0
  109. package/dist/src/learning/MeasurementEvidenceConflicts.test.js +78 -0
  110. package/dist/src/learning/PublicAnswerContract.test.js +85 -0
  111. package/dist/src/learning/PublicEvidenceSelection.test.js +94 -0
  112. package/dist/src/learning/PublicMeasurementDisclosure.test.js +54 -0
  113. package/dist/src/learning/agentConversationExecution.js +211 -0
  114. package/dist/src/learning/agentConversationExecution.test.js +209 -0
  115. package/dist/src/learning/agentConversationSerialization.js +266 -0
  116. package/dist/src/learning/agentConversationSerialization.test.js +165 -0
  117. package/dist/src/learning/agentResponseBudget.js +179 -0
  118. package/dist/src/learning/agentResponseBudget.test.js +97 -0
  119. package/dist/src/learning/agentWorkspaceCapabilityContracts.js +65 -0
  120. package/dist/src/learning/answerReleaseReview.js +5260 -0
  121. package/dist/src/learning/answerReleaseReview.test.js +4174 -0
  122. package/dist/src/learning/answerTaskPlan.js +473 -0
  123. package/dist/src/learning/api.js +2 -0
  124. package/dist/src/learning/conversationComposer.js +1721 -0
  125. package/dist/src/learning/conversationComposer.test.js +3220 -0
  126. package/dist/src/learning/domains/ConversationManager.js +53 -0
  127. package/dist/src/learning/domains/KnowledgeIngestor.js +238 -0
  128. package/dist/src/learning/domains/KnowledgeQuerier.js +187 -0
  129. package/dist/src/learning/domains/MasteryEngine.js +387 -0
  130. package/dist/src/learning/domains/MemoryPolicyManager.js +408 -0
  131. package/dist/src/learning/domains/QualityEvaluator.js +307 -0
  132. package/dist/src/learning/domains/TutorRouter.js +313 -0
  133. package/dist/src/learning/domains/index.js +33 -0
  134. package/dist/src/learning/domains/types.js +7 -0
  135. package/dist/src/learning/errors.js +29 -0
  136. package/dist/src/learning/evidenceContextAssembler.js +1368 -0
  137. package/dist/src/learning/evidenceContextAssembler.test.js +6332 -0
  138. package/dist/src/learning/graphAnswerCoverage.js +37 -0
  139. package/dist/src/learning/graphAnswerCoverage.test.js +93 -0
  140. package/dist/src/learning/graphAnswerCoverageCalibration.js +59 -0
  141. package/dist/src/learning/graphAnswerCoverageCalibration.test.js +46 -0
  142. package/dist/src/learning/graphAnswerFacts.js +94 -0
  143. package/dist/src/learning/graphAnswerFacts.test.js +39 -0
  144. package/dist/src/learning/graphAnswerPlan.js +908 -0
  145. package/dist/src/learning/graphAnswerPlan.test.js +907 -0
  146. package/dist/src/learning/graphAnswerQualityCalibration.js +255 -0
  147. package/dist/src/learning/graphAnswerQualityCalibration.test.js +72 -0
  148. package/dist/src/learning/graphAnswerQualityPolicy.js +30 -0
  149. package/dist/src/learning/graphClaimMatcher.js +104 -0
  150. package/dist/src/learning/graphConditionedContext.js +109 -0
  151. package/dist/src/learning/graphConditionedContext.test.js +99 -0
  152. package/dist/src/learning/graphContextAssembler.js +860 -0
  153. package/dist/src/learning/graphContextAssembler.test.js +1033 -0
  154. package/dist/src/learning/graphExpansionPolicy.js +22 -0
  155. package/dist/src/learning/graphExpansionPolicy.test.js +33 -0
  156. package/dist/src/learning/identityMetadata.test.js +26 -0
  157. package/dist/src/learning/index.js +29 -0
  158. package/dist/src/learning/mobileAnswerProjection.js +104 -0
  159. package/dist/src/learning/mobileAnswerProjection.test.js +102 -0
  160. package/dist/src/learning/queryBackend.js +1922 -0
  161. package/dist/src/learning/queryBackend.test.js +976 -0
  162. package/dist/src/learning/ragContextPack.js +356 -0
  163. package/dist/src/learning/ragContextPack.test.js +311 -0
  164. package/dist/src/learning/ragEvidenceQuality.js +96 -0
  165. package/dist/src/learning/ragEvidenceQuality.test.js +29 -0
  166. package/dist/src/learning/ragPublicText.js +101 -0
  167. package/dist/src/learning/ragPublicText.test.js +57 -0
  168. package/dist/src/learning/ragSufficiencyJudge.js +171 -0
  169. package/dist/src/learning/ragSufficiencyJudge.test.js +177 -0
  170. package/dist/src/learning/ragSufficiencyProviderJudge.js +217 -0
  171. package/dist/src/learning/ragSufficiencyProviderJudge.test.js +207 -0
  172. package/dist/src/learning/requestNormalization.js +304 -0
  173. package/dist/src/learning/requestNormalization.test.js +101 -0
  174. package/dist/src/learning/runtimeCapability.js +4677 -0
  175. package/dist/src/learning/runtimeCapability.test.js +3635 -0
  176. package/dist/src/learning/store.js +1344 -0
  177. package/dist/src/learning/store.test.js +1425 -0
  178. package/dist/src/learning/tutorAdapter.js +2 -0
  179. package/dist/src/learning/types.js +2 -0
  180. package/dist/src/learning/vectorAccelerationAdapter.js +958 -0
  181. package/dist/src/learning/vectorAccelerationAdapter.test.js +412 -0
  182. package/dist/src/learning/workspaceHydration.js +168 -0
  183. package/dist/src/learning/workspaceHydration.test.js +30 -0
  184. package/dist/src/lfs.asset.policy.contract.test.js +153 -0
  185. package/dist/src/license.policy.contract.test.js +71 -0
  186. package/dist/src/markdown/MarkdownGateway.js +4 -0
  187. package/dist/src/markdown/MarkdownGateway.test.js +59 -0
  188. package/dist/src/memory/MemoryGovernance.js +74 -0
  189. package/dist/src/memory/MemoryGovernance.test.js +46 -0
  190. package/dist/src/memory/types.js +2 -0
  191. package/dist/src/mermaid.frontend.guard.contract.test.js +77 -0
  192. package/dist/src/middleware/SseResponseWriter.js +122 -0
  193. package/dist/src/middleware/SseResponseWriter.test.js +54 -0
  194. package/dist/src/middleware/auth.js +38 -0
  195. package/dist/src/middleware/auth.test.js +33 -0
  196. package/dist/src/middleware/body-parser.js +45 -0
  197. package/dist/src/middleware/cors.js +44 -0
  198. package/dist/src/middleware/index.js +22 -0
  199. package/dist/src/middleware/request-trace.js +96 -0
  200. package/dist/src/mobile.android.evidence.contract.test.js +146 -0
  201. package/dist/src/mobile.android.signing.contract.test.js +66 -0
  202. package/dist/src/mobile.artifact.contract.test.js +144 -0
  203. package/dist/src/mobile.budget.contract.test.js +90 -0
  204. package/dist/src/mobile.canonical-id.readiness.test.js +54 -0
  205. package/dist/src/mobile.graph.parity.contract.test.js +207 -0
  206. package/dist/src/mobile.identity.contract.test.js +66 -0
  207. package/dist/src/mobile.identity.corpus.manifest.test.js +72 -0
  208. package/dist/src/mobile.identity.corpus.test.js +40 -0
  209. package/dist/src/mobile.native.recovery.contract.test.js +64 -0
  210. package/dist/src/mobile.pipeline.test.js +11 -1
  211. package/dist/src/mobile.profile.contract.test.js +225 -0
  212. package/dist/src/mobile.semantic.parity.test.js +92 -0
  213. package/dist/src/mobile_exact_analyzer.test.js +113 -0
  214. package/dist/src/notemd/AppConfigToml.js +6 -4
  215. package/dist/src/notemd/ContentGenerator.js +4 -9
  216. package/dist/src/notemd/FileProcessor.js +4 -9
  217. package/dist/src/notemd/MermaidProcessor.js +400 -50
  218. package/dist/src/notemd/NotemdService.js +506 -26
  219. package/dist/src/notemd/PromptManager.js +15 -0
  220. package/dist/src/notemd/Translator.js +4 -9
  221. package/dist/src/notemd/cli/commands.js +357 -0
  222. package/dist/src/notemd/cli/dispatcher.js +225 -0
  223. package/dist/src/notemd/cli/index.js +169 -0
  224. package/dist/src/notemd/cli/parser.js +68 -0
  225. package/dist/src/notemd/cli/types.js +2 -0
  226. package/dist/src/notemd/constants.js +43 -0
  227. package/dist/src/notemd/diagram/diagramGenerationService.js +78 -0
  228. package/dist/src/notemd/diagram/diagramSpec.js +79 -0
  229. package/dist/src/notemd/diagram/diagramSpecResponseParser.js +131 -0
  230. package/dist/src/notemd/diagram/intent.js +95 -0
  231. package/dist/src/notemd/diagram/planner.js +71 -0
  232. package/dist/src/notemd/diagram/prompts/diagramSpecPrompt.js +42 -0
  233. package/dist/src/notemd/diagram/types.js +18 -0
  234. package/dist/src/notemd/index.js +26 -0
  235. package/dist/src/notemd/operations/capabilityManifest.js +23 -0
  236. package/dist/src/notemd/operations/cliContracts.js +17 -0
  237. package/dist/src/notemd/operations/configProfileCommands.js +85 -0
  238. package/dist/src/notemd/operations/registry.contract.test.js +95 -0
  239. package/dist/src/notemd/operations/registry.js +991 -0
  240. package/dist/src/notemd/operations/types.js +2 -0
  241. package/dist/src/notemd/progressReporter.js +9 -0
  242. package/dist/src/notemd/providerDiagnostics.js +220 -0
  243. package/dist/src/notemd/providerProfiles.js +42 -0
  244. package/dist/src/notemd/providerTemplates.js +231 -0
  245. package/dist/src/notemd/search/DuckDuckGoProvider.js +39 -0
  246. package/dist/src/notemd/search/SearchManager.js +13 -0
  247. package/dist/src/notemd/search/SearchProvider.js +2 -0
  248. package/dist/src/notemd/search/TavilyProvider.js +44 -0
  249. package/dist/src/notemd.agent.manifest.test.js +85 -0
  250. package/dist/src/notemd.api.contract.test.js +14 -1
  251. package/dist/src/notemd.app_config_toml.test.js +2 -1
  252. package/dist/src/notemd.batch.workflow.test.js +117 -0
  253. package/dist/src/notemd.cli.e2e.test.js +136 -0
  254. package/dist/src/notemd.core.test.js +51 -0
  255. package/dist/src/notemd.diagram.pipeline.test.js +233 -0
  256. package/dist/src/notemd.providerTemplates.test.js +34 -0
  257. package/dist/src/notemd.server.integration.test.js +262 -39
  258. package/dist/src/notemd.workflow.pipeline.test.js +162 -0
  259. package/dist/src/pathbridge.handshake.contract.test.js +45 -2
  260. package/dist/src/pathbridge.host-adapter.contract.test.js +133 -0
  261. package/dist/src/pathcore.bundle.contract.test.js +8 -0
  262. package/dist/src/pathmode.background.contract.test.js +69 -0
  263. package/dist/src/pathmode.settings.api.contract.test.js +9 -0
  264. package/dist/src/pkg.sidecar.contract.test.js +9 -3
  265. package/dist/src/platform/ExportProfile.js +86 -0
  266. package/dist/src/platform/MobileBudget.js +11 -0
  267. package/dist/src/platform/PlatformCapabilities.js +59 -0
  268. package/dist/src/platform/PlatformCapabilities.test.js +36 -0
  269. package/dist/src/platform/RenderMaterializer.js +33 -0
  270. package/dist/src/platform/RenderMaterializer.test.js +32 -0
  271. package/dist/src/query_backend.external_http.integration.test.js +410 -0
  272. package/dist/src/reader_renderer.js +404 -3
  273. package/dist/src/reader_renderer.test.js +87 -0
  274. package/dist/src/release.godot.mirror.contract.test.js +97 -0
  275. package/dist/src/resources/ResourceRegistry.js +263 -0
  276. package/dist/src/resources/ResourceRegistry.test.js +97 -0
  277. package/dist/src/resources/types.js +2 -0
  278. package/dist/src/routes/agentWorkspaceDiagnostics.js +173 -0
  279. package/dist/src/routes/index.js +19 -0
  280. package/dist/src/routes/knowledge.js +981 -0
  281. package/dist/src/routes/knowledgePayload.js +185 -0
  282. package/dist/src/routes/knowledgePayload.test.js +53 -0
  283. package/dist/src/routes/markdown.js +295 -0
  284. package/dist/src/routes/notemd.js +1321 -0
  285. package/dist/src/routes/registry.contract.test.js +133 -0
  286. package/dist/src/routes/registry.shadow.contract.test.js +22 -0
  287. package/dist/src/routes/render.js +248 -0
  288. package/dist/src/routes/runtimeRunbookRouteOps.js +149 -0
  289. package/dist/src/routes/runtimeRunbookRouteOps.test.js +194 -0
  290. package/dist/src/routes/settings.js +6 -0
  291. package/dist/src/routes/staticFiles.js +94 -0
  292. package/dist/src/routes/types.js +2 -0
  293. package/dist/src/runtime.capabilities.test.js +18 -2
  294. package/dist/src/runtime.transport.adapter.contract.test.js +81 -0
  295. package/dist/src/server.js +10342 -1325
  296. package/dist/src/server.migration.test.js +584 -10
  297. package/dist/src/server.port.fallback.contract.test.js +63 -0
  298. package/dist/src/session/SessionStateStore.js +81 -0
  299. package/dist/src/session/SessionStateStore.test.js +58 -0
  300. package/dist/src/session/types.js +2 -0
  301. package/dist/src/settings.runtime.contract.test.js +50 -0
  302. package/dist/src/shared/types.contract.test.js +107 -0
  303. package/dist/src/shared/types.js +22 -0
  304. package/dist/src/sidecar.build.lock.contract.test.js +201 -0
  305. package/dist/src/sidecar.freshness.contract.test.js +184 -0
  306. package/dist/src/sidecar.replacement.boundary.contract.test.js +131 -0
  307. package/dist/src/sidecar.supply.readiness.contract.test.js +155 -0
  308. package/dist/src/simulation.worker.offline.test.js +104 -0
  309. package/dist/src/source_manager.loadflow.test.js +46 -0
  310. package/dist/src/startup.layout.snapshot.contract.test.js +57 -0
  311. package/dist/src/storage.provider.capacitor.content.contract.test.js +4 -1
  312. package/dist/src/storage.provider.contract.test.js +152 -1
  313. package/dist/src/tauri.frontend.build.contract.test.js +68 -0
  314. package/dist/src/tauri.sidecar.cleanup.contract.test.js +21 -0
  315. package/dist/src/tauri.window.evidence.execution.test.js +68 -0
  316. package/dist/src/utils/RuntimePaths.js +10 -13
  317. package/dist/src/utils/RuntimePaths.test.js +27 -0
  318. package/dist/src/utils/platform.js +153 -0
  319. package/dist/src/windows.installer.build.test.js +109 -0
  320. package/dist/src/windows.installer.payload.test.js +76 -0
  321. package/dist/src/windows.installer.runtime.test.js +69 -0
  322. package/dist/src/workflows/WorkflowArtifactStore.js +96 -0
  323. package/dist/src/workflows/WorkflowArtifactStore.test.js +80 -0
  324. package/dist/src/workflows/types.js +2 -0
  325. package/dist/src/workspace/WorkspaceRegistry.js +135 -0
  326. package/dist/src/workspace/WorkspaceRegistry.test.js +29 -0
  327. package/dist/src/workspace/types.js +2 -0
  328. package/package.json +80 -15
@@ -0,0 +1,134 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ const path = __importStar(require("path"));
37
+ const contract = require(path.resolve(__dirname, 'frontend', 'knowledge_projection_contract.js'));
38
+ describe('versioned knowledge projection contract', () => {
39
+ test('creates a body-free projection with identity, provenance, evidence, and bounded adjacency', () => {
40
+ const projection = contract.createKnowledgeProjection({
41
+ nodes: [
42
+ {
43
+ id: 'Legacy A',
44
+ label: 'A',
45
+ content: 'must not be persisted',
46
+ sourceUri: 'note://workspace/v1/a.md',
47
+ revision: 'sha256:abc',
48
+ identityAliases: ['a.md'],
49
+ evidenceRefs: ['span:1'],
50
+ metadata: { tags: ['algebra'] },
51
+ },
52
+ { id: 'B', label: 'B' },
53
+ ],
54
+ edges: [
55
+ { source: 'Legacy A', target: 'B', type: 'explicit-prerequisite', evidenceRefs: ['span:2'] },
56
+ ],
57
+ }, { workspaceId: 'mobile-workspace', maxNeighbors: 1 });
58
+ expect(projection).toEqual(expect.objectContaining({
59
+ schemaVersion: 1,
60
+ projectionVersion: 1,
61
+ workspaceId: 'mobile-workspace',
62
+ }));
63
+ expect(projection.nodes[0]).toEqual(expect.objectContaining({
64
+ sourceUri: 'note://workspace/v1/a.md',
65
+ revision: 'sha256:abc',
66
+ evidenceRefs: ['span:1'],
67
+ tags: ['algebra'],
68
+ }));
69
+ expect(projection.nodes[0].content).toBeUndefined();
70
+ expect(projection.edges[0]).toEqual(expect.objectContaining({
71
+ kind: 'explicit',
72
+ provenance: 'explicit-prerequisite',
73
+ sourceUri: 'note://workspace/v1/a.md',
74
+ targetUri: '',
75
+ evidenceRefs: ['span:2'],
76
+ }));
77
+ expect(projection.adjacency).toEqual(expect.arrayContaining([
78
+ expect.objectContaining({ nodeId: 'Legacy A', outgoing: ['B'] }),
79
+ ]));
80
+ });
81
+ test('replays the same serialized projection and rejects unknown future schemas', () => {
82
+ const projection = contract.createKnowledgeProjection({
83
+ nodes: [{ id: 'A', sourceUri: 'note://workspace/v1/a.md' }],
84
+ edges: [],
85
+ });
86
+ const replayed = contract.replayKnowledgeProjection(JSON.stringify(projection));
87
+ expect(replayed).toEqual(projection);
88
+ expect(() => contract.replayKnowledgeProjection({ schemaVersion: contract.schemaVersion + 1, nodes: [], edges: [] }))
89
+ .toThrow(/Unsupported knowledge projection schema version/);
90
+ expect(() => contract.replayKnowledgeProjection({ schemaVersion: 0, nodes: [], edges: [] }))
91
+ .toThrow(/Unsupported knowledge projection schema version/);
92
+ });
93
+ test('preserves graph-level identity metadata when no override is supplied', () => {
94
+ const projection = contract.createKnowledgeProjection({
95
+ workspaceId: 'source-workspace',
96
+ revision: 'sha256:graph',
97
+ nodes: [{ id: 'A' }],
98
+ edges: [],
99
+ });
100
+ expect(projection.workspaceId).toBe('source-workspace');
101
+ expect(projection.revision).toBe('sha256:graph');
102
+ });
103
+ test('fails closed on normalized identity collisions and invalid edge endpoints', () => {
104
+ expect(() => contract.createKnowledgeProjection({
105
+ nodes: [{ id: 'A' }, { id: 'a' }],
106
+ edges: [],
107
+ })).toThrow(/duplicate node id/i);
108
+ expect(() => contract.createKnowledgeProjection({
109
+ nodes: [{ id: 'A' }],
110
+ edges: [{ source: 'A', target: 'missing', type: 'explicit-next' }],
111
+ })).toThrow(/invalid node/i);
112
+ expect(() => contract.createKnowledgeProjection({
113
+ nodes: [
114
+ { id: 'A', canonicalId: 'notes/a' },
115
+ { id: 'B', canonicalId: 'NOTES/A' },
116
+ ],
117
+ edges: [],
118
+ })).toThrow(/duplicate canonical node id/i);
119
+ });
120
+ test('preserves distinct provenance for same-endpoint edges', () => {
121
+ const projection = contract.createKnowledgeProjection({
122
+ nodes: [{ id: 'A' }, { id: 'B' }],
123
+ edges: [
124
+ { source: 'A', target: 'B', type: 'wiki-link', provenance: 'wiki-link' },
125
+ { source: 'A', target: 'B', type: 'markdown-link', provenance: 'markdown-link' },
126
+ ],
127
+ });
128
+ expect(projection.edges).toHaveLength(2);
129
+ expect(projection.edges.map((edge) => edge.provenance)).toEqual([
130
+ 'wiki-link',
131
+ 'markdown-link',
132
+ ]);
133
+ });
134
+ });
@@ -0,0 +1,200 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ const fs = __importStar(require("fs"));
37
+ const os = __importStar(require("os"));
38
+ const path = __importStar(require("path"));
39
+ const projectionContract = require(path.resolve(__dirname, 'frontend', 'knowledge_projection_contract.js'));
40
+ const projectionStore = require(path.resolve(__dirname, 'frontend', 'knowledge_projection_store.js'));
41
+ const exactAnalyzer = require(path.resolve(__dirname, 'frontend', 'mobile_exact_analyzer.js'));
42
+ function createFixture() {
43
+ return projectionContract.createKnowledgeProjection({
44
+ workspaceId: 'fixture-workspace',
45
+ revision: 'sha256:fixture',
46
+ nodes: [
47
+ { id: 'A', label: 'Algebra', sourceUri: 'note://workspace/v1/algebra.md', identityAliases: ['algebra.md'] },
48
+ { id: 'B', label: 'Basics', sourceUri: 'note://workspace/v1/basics.md' },
49
+ { id: 'C', label: 'Calculus', sourceUri: 'note://workspace/v1/calculus.md' },
50
+ ],
51
+ edges: [
52
+ { source: 'A', target: 'B', type: 'explicit-prerequisite', evidenceRefs: ['span:a-b'] },
53
+ { source: 'B', target: 'C', type: 'explicit-prerequisite', evidenceRefs: ['span:b-c'] },
54
+ ],
55
+ });
56
+ }
57
+ describe('cross-host knowledge projection store', () => {
58
+ test('replays identical schema, metadata, search, neighbors, and path results', async () => {
59
+ const fixture = createFixture();
60
+ let persisted = JSON.stringify(fixture);
61
+ const hostStores = ['web', 'tauri', 'capacitor', 'android'].map((host) => ({
62
+ host,
63
+ store: projectionStore.createProjectionStore({
64
+ read: async () => persisted,
65
+ write: async (serialized) => {
66
+ persisted = serialized;
67
+ },
68
+ }),
69
+ }));
70
+ const baseline = {
71
+ projection: fixture,
72
+ metadata: await hostStores[0].store.metadata(),
73
+ search: exactAnalyzer.createMobileExactIndex(fixture).searchExact('Algebra', 10),
74
+ neighbors: exactAnalyzer.createMobileExactIndex(fixture).neighbors('A', 10),
75
+ path: exactAnalyzer.createMobileExactIndex(fixture).shortestPath('A', 'C', 8, 100),
76
+ };
77
+ for (const { host, store } of hostStores) {
78
+ const projection = await store.load();
79
+ const index = exactAnalyzer.createMobileExactIndex(projection);
80
+ expect(projection).toEqual(baseline.projection);
81
+ expect(await store.metadata()).toEqual(baseline.metadata);
82
+ expect(index.searchExact('Algebra', 10)).toEqual(baseline.search);
83
+ expect(index.neighbors('A', 10)).toEqual(baseline.neighbors);
84
+ expect(index.shortestPath('A', 'C', 8, 100)).toEqual(baseline.path);
85
+ expect(host).toMatch(/web|tauri|capacitor|android/);
86
+ }
87
+ });
88
+ test('keeps a successful in-memory projection available during adapter failure', async () => {
89
+ const fixture = createFixture();
90
+ const store = projectionStore.createProjectionStore({
91
+ read: async () => { throw new Error('storage temporarily unavailable'); },
92
+ initialProjection: fixture,
93
+ });
94
+ await expect(store.load()).resolves.toEqual(fixture);
95
+ await expect(store.metadata()).resolves.toEqual(expect.objectContaining({
96
+ nodeCount: 3,
97
+ edgeCount: 2,
98
+ }));
99
+ });
100
+ test('fails closed on an unknown future schema instead of silently downgrading', async () => {
101
+ const store = projectionStore.createProjectionStore({
102
+ read: async () => JSON.stringify({ schemaVersion: 2, nodes: [], edges: [] }),
103
+ });
104
+ await expect(store.load()).rejects.toThrow(/Unsupported knowledge projection schema version/);
105
+ });
106
+ test('does not hide a corrupt or future projection behind a stale cache', async () => {
107
+ const fixture = createFixture();
108
+ const store = projectionStore.createProjectionStore({
109
+ initialProjection: fixture,
110
+ read: async () => JSON.stringify({ schemaVersion: 2, nodes: [], edges: [] }),
111
+ });
112
+ await expect(store.load()).rejects.toThrow(/Unsupported knowledge projection schema version/);
113
+ await expect(store.metadata()).rejects.toThrow(/Unsupported knowledge projection schema version/);
114
+ });
115
+ test('reopens an app-local file projection with identical analysis results', async () => {
116
+ const fixture = createFixture();
117
+ const tempRoot = await fs.promises.mkdtemp(path.join(os.tmpdir(), 'noteconnection-projection-'));
118
+ const projectionPath = path.join(tempRoot, 'graph_data.json');
119
+ const createStore = () => projectionStore.createFileProjectionStore({
120
+ fileName: projectionPath,
121
+ readFile: async (fileName) => await fs.promises.readFile(fileName, 'utf8'),
122
+ writeAtomic: async (fileName, serialized) => {
123
+ const temporaryPath = `${fileName}.tmp-${process.pid}-${Date.now()}`;
124
+ await fs.promises.writeFile(temporaryPath, serialized, 'utf8');
125
+ await fs.promises.rename(temporaryPath, fileName);
126
+ },
127
+ });
128
+ try {
129
+ const firstStore = createStore();
130
+ expect(firstStore.kind).toBe('file-persistent');
131
+ await firstStore.save(fixture);
132
+ const reopenedStore = createStore();
133
+ const replayed = await reopenedStore.load();
134
+ const baselineIndex = exactAnalyzer.createMobileExactIndex(fixture);
135
+ const replayedIndex = exactAnalyzer.createMobileExactIndex(replayed);
136
+ expect(replayed).toEqual(fixture);
137
+ expect(await reopenedStore.metadata()).toEqual(await firstStore.metadata());
138
+ expect(replayedIndex.searchExact('Algebra', 10)).toEqual(baselineIndex.searchExact('Algebra', 10));
139
+ expect(replayedIndex.neighbors('A', 10)).toEqual(baselineIndex.neighbors('A', 10));
140
+ expect(replayedIndex.shortestPath('A', 'C', 8, 100)).toEqual(baselineIndex.shortestPath('A', 'C', 8, 100));
141
+ }
142
+ finally {
143
+ await fs.promises.rm(tempRoot, { recursive: true, force: true });
144
+ }
145
+ });
146
+ test('keeps the last committed file when an atomic write fails', async () => {
147
+ const fixture = createFixture();
148
+ const tempRoot = await fs.promises.mkdtemp(path.join(os.tmpdir(), 'noteconnection-projection-'));
149
+ const projectionPath = path.join(tempRoot, 'graph_data.json');
150
+ let failWrites = false;
151
+ const createStore = () => projectionStore.createFileProjectionStore({
152
+ fileName: projectionPath,
153
+ readFile: async (fileName) => await fs.promises.readFile(fileName, 'utf8'),
154
+ writeAtomic: async (fileName, serialized) => {
155
+ if (failWrites) {
156
+ throw new Error('storage unavailable');
157
+ }
158
+ const temporaryPath = `${fileName}.tmp-${process.pid}-${Date.now()}`;
159
+ await fs.promises.writeFile(temporaryPath, serialized, 'utf8');
160
+ await fs.promises.rename(temporaryPath, fileName);
161
+ },
162
+ });
163
+ try {
164
+ const committedStore = createStore();
165
+ await committedStore.save(fixture);
166
+ failWrites = true;
167
+ await expect(committedStore.save({ ...fixture, revision: 'sha256:next' })).rejects.toThrow(/storage unavailable/);
168
+ const reopenedStore = createStore();
169
+ await expect(reopenedStore.load()).resolves.toEqual(fixture);
170
+ }
171
+ finally {
172
+ await fs.promises.rm(tempRoot, { recursive: true, force: true });
173
+ }
174
+ });
175
+ test('rejects truncated app-local files instead of replaying partial JSON', async () => {
176
+ const tempRoot = await fs.promises.mkdtemp(path.join(os.tmpdir(), 'noteconnection-projection-'));
177
+ const projectionPath = path.join(tempRoot, 'graph_data.json');
178
+ try {
179
+ await fs.promises.writeFile(projectionPath, '{"schemaVersion":1,"nodes":[', 'utf8');
180
+ const store = projectionStore.createFileProjectionStore({
181
+ fileName: projectionPath,
182
+ readFile: async (fileName) => await fs.promises.readFile(fileName, 'utf8'),
183
+ });
184
+ await expect(store.load()).rejects.toThrow(/Knowledge projection JSON is invalid/);
185
+ }
186
+ finally {
187
+ await fs.promises.rm(tempRoot, { recursive: true, force: true });
188
+ }
189
+ });
190
+ test('rejects an incomplete app-local adapter instead of silently switching to memory', () => {
191
+ expect(() => projectionStore.createFileProjectionStore({
192
+ fileName: 'graph_data.json',
193
+ })).toThrow(/readFile adapter is required/);
194
+ expect(() => projectionStore.createFileProjectionStore({
195
+ fileName: 'graph_data.json',
196
+ readFile: async () => '',
197
+ write: async () => undefined,
198
+ })).toThrow(/must use the writeAtomic adapter/);
199
+ });
200
+ });
@@ -0,0 +1,153 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ANSWER_QUALITY_CATEGORIES = exports.ANSWER_QUALITY_MEASUREMENT_PROTOCOL = void 0;
4
+ exports.parseAnswerQualityCorpus = parseAnswerQualityCorpus;
5
+ exports.measureAnswerQuality = measureAnswerQuality;
6
+ exports.summarizeAnswerQuality = summarizeAnswerQuality;
7
+ // Legacy reports without a protocol field used the release label and a narrower no-answer vocabulary.
8
+ exports.ANSWER_QUALITY_MEASUREMENT_PROTOCOL = 'answer-quality-public-surface-v3';
9
+ exports.ANSWER_QUALITY_CATEGORIES = [
10
+ 'definition', 'comparison', 'causal', 'multi_step', 'conflict', 'missing_evidence', 'topic_drift', 'math', 'noisy_headings',
11
+ ];
12
+ function parseAnswerQualityCorpus(input) {
13
+ if (!input || typeof input !== 'object' || Array.isArray(input))
14
+ throw new TypeError('Expected an answer-quality corpus object');
15
+ const corpus = input;
16
+ if (corpus.schemaVersion !== 1 || !corpus.version || !corpus.backend || !Array.isArray(corpus.cases) || !corpus.cases.length) {
17
+ throw new TypeError('Incomplete answer-quality corpus contract');
18
+ }
19
+ const caseIds = new Set();
20
+ const documentIds = new Set();
21
+ const sourceContents = new Map();
22
+ for (const entry of corpus.cases) {
23
+ if (!entry.id || caseIds.has(entry.id) || !['calibration', 'evaluation'].includes(entry.split)
24
+ || !['en', 'zh'].includes(entry.language) || !exports.ANSWER_QUALITY_CATEGORIES.includes(entry.category)
25
+ || typeof entry.query !== 'string' || !entry.query.trim() || !Array.isArray(entry.documents) || !entry.documents.length) {
26
+ throw new TypeError(`Invalid or duplicate answer-quality case: ${entry.id}`);
27
+ }
28
+ caseIds.add(entry.id);
29
+ for (const document of entry.documents) {
30
+ if (!document.documentId || documentIds.has(document.documentId) || !document.sourcePath || typeof document.content !== 'string') {
31
+ throw new TypeError(`Invalid or duplicate document in case ${entry.id}`);
32
+ }
33
+ documentIds.add(document.documentId);
34
+ const content = document.content.replace(/\s+/g, ' ').trim();
35
+ const previousSplit = sourceContents.get(content);
36
+ if (previousSplit && previousSplit !== entry.split)
37
+ throw new TypeError('Calibration/evaluation source leakage');
38
+ sourceContents.set(content, entry.split);
39
+ }
40
+ const reference = entry.reference;
41
+ if (!reference || !Array.isArray(reference.facts) || !Array.isArray(reference.unsupportedClaims)
42
+ || typeof reference.expectsConflict !== 'boolean' || typeof reference.expectsAbstention !== 'boolean') {
43
+ throw new TypeError(`Missing independent references for ${entry.id}`);
44
+ }
45
+ const patterns = [];
46
+ for (const fact of reference.facts) {
47
+ if (!fact.id || !Array.isArray(fact.patterns) || !fact.patterns.length)
48
+ throw new TypeError(`Invalid fact in ${entry.id}`);
49
+ patterns.push(...fact.patterns);
50
+ }
51
+ for (const claim of reference.unsupportedClaims) {
52
+ if (!claim.id)
53
+ throw new TypeError(`Invalid unsupported-claim probe in ${entry.id}`);
54
+ patterns.push(claim.pattern);
55
+ }
56
+ if (reference.orderedSteps) {
57
+ if (!Array.isArray(reference.orderedSteps))
58
+ throw new TypeError(`Invalid ordered steps in ${entry.id}`);
59
+ patterns.push(...reference.orderedSteps);
60
+ }
61
+ for (const pattern of patterns) {
62
+ if (typeof pattern !== 'string' || !pattern || pattern.length > 512)
63
+ throw new TypeError(`Invalid reference pattern in ${entry.id}`);
64
+ new RegExp(pattern, 'iu');
65
+ }
66
+ }
67
+ return corpus;
68
+ }
69
+ function publicAnswerSignalsAbstention(answer) {
70
+ if (/insufficient (?:local |source )?evidence|no (?:scoped|relevant|matching) (?:knowledge|evidence)|证据不足|没有(?:足够|相关)证据|暂无相关证据/iu.test(answer))
71
+ return true;
72
+ if (/\b(?:i|we) (?:cannot|can't|can’t|could not) (?:answer|(?:give|provide) (?:a )?(?:grounded|reliable|supported) answer)/iu.test(answer)
73
+ || /我(?:暂时)?(?:不能|无法)对“[^”]*”给出有依据的回答/u.test(answer)
74
+ || /(?:资料|证据|材料|信息)不足以(?:确定|给出|回答)|我(?:暂时)?(?:不能|无法)[^。!?]{0,160}(?:有依据的回答|确定)/u.test(answer))
75
+ return true;
76
+ // The missing object must be a measurement. "No data loss" and negative
77
+ // capability statements are factual answers, not evidence of abstention.
78
+ const source = String.raw `\b(?:archives?|sources?|notes?|records?|reports?|evidence|documents?|documentation|materials?|datasets?)\b`;
79
+ const measurement = String.raw `\b(?:measurements?|measured (?:values?|data|melting points?)|measurement (?:data|results?)|melting points?|parameter values?|requested data)\b`;
80
+ const object = String.raw `\s+(?:(?:a|an|the|any|reliable|available|recorded|relevant|usable|experimental|exact|requested|[\w-]+['’]s)\s+){0,5}`;
81
+ const absentMeasurement = [
82
+ `${source}\\s+(?:does not|do not|did not|doesn't|doesn’t|has not|have not)\\s+(?:provide|contain|record|report|specify|document|include|state)\\b${object}${measurement}`,
83
+ `${source}\\s+(?:contains?|provides?|records?|reports?|includes?|has|have)\\s+no${object}${measurement}`,
84
+ `${measurement}\\s+(?:has not been|have not been|is not|are not|was not|were not)\\s+(?:recorded|reported|provided|documented|available)\\b`,
85
+ ];
86
+ if (absentMeasurement.some(pattern => new RegExp(pattern, 'iu').test(answer)))
87
+ return true;
88
+ return /(?:档案|存档|资料|材料|笔记|文档|记录|报告|来源)(?:中|里)?(?:尚未|未|并未)(?:提供|给出|记录|收录|报告|标明|包含|测得)[^,,。!?;;]{0,80}(?:测量(?:值|数据|结果)?|实验数据|参数值|熔点|数值)/u.test(answer)
89
+ || /(?:档案|存档|资料|材料|笔记|文档|记录|报告|来源)(?:中|里)?(?:没有|暂无)(?:提供|给出|记录|收录|报告|标明|包含)?[^,,。!?;;]{0,80}(?:测量(?:值|数据|结果)?|实验数据|参数值|熔点|数值)/u.test(answer);
90
+ }
91
+ function publicAnswerSignalsEvidenceConflict(answer) {
92
+ const text = answer.replace(/\b(?:no|without)\s+(?:evidence of\s+)?(?:conflicts?|conflicting|contradictions?|contradictory|inconsistenc(?:y|ies)|inconsistent)\b/giu, '')
93
+ .replace(/(?:没有|不存在|无)(?:明显)?(?:冲突|矛盾|分歧)/gu, '');
94
+ // A conflict between sources is different from a fact about write conflicts,
95
+ // hash collisions or conflict serializability. Require a disclosure about evidence.
96
+ return /\b(?:sources?|evidence|observations?|measurements?|reports?|statements?)\s+(?:(?:is|are|was|were|remain|remains|appear|appears|seem|seems)\s+)?(?:in\s+conflict|conflict(?:s|ing)?|contradict(?:s|ory)?|disagree(?:s)?|inconsistent)\b/iu.test(text)
97
+ || /\b(?:conflicting|contradictory|inconsistent)\s+(?:source\s+)?(?:evidence|observations?|measurements?|reports?|statements?|sources?)\b/iu.test(text)
98
+ || /\b(?:conflict|contradiction|disagreement|inconsistency)\s+(?:between|among)\s+(?:the\s+)?(?:source\s+)?(?:evidence|observations?|measurements?|reports?|statements?|sources?)\b/iu.test(text)
99
+ || /(?:来源|证据|观测(?:结果)?|测量(?:值|记录))(?:之间|彼此|相互|中的观测|中的记录|中|结果)?(?:存在|出现|发生|有|相互|互相|彼此)?(?:冲突|矛盾|分歧|不一致)/u.test(text)
100
+ || /(?:报告|记录|陈述)(?:之间|彼此|相互)(?:存在|出现|发生|有)?(?:冲突|矛盾|分歧|不一致)/u.test(text);
101
+ }
102
+ function measureAnswerQuality(entry, response) {
103
+ const answer = response.answer.replace(/\*\*|`/g, '').replace(/\s+/g, ' ').trim();
104
+ const matches = (pattern) => new RegExp(pattern, 'iu').test(answer);
105
+ const coveredFactIds = entry.reference.facts.filter(fact => fact.patterns.some(matches)).map(fact => fact.id);
106
+ const missingFactIds = entry.reference.facts.filter(fact => !coveredFactIds.includes(fact.id)).map(fact => fact.id);
107
+ const unsupportedClaimIds = entry.reference.unsupportedClaims.filter(claim => matches(claim.pattern)).map(claim => claim.id);
108
+ const conflictSignalled = publicAnswerSignalsEvidenceConflict(answer);
109
+ const abstentionSignalled = publicAnswerSignalsAbstention(answer);
110
+ let stepOffset = 0;
111
+ const orderedStepsSatisfied = (entry.reference.orderedSteps || []).every(pattern => {
112
+ const match = new RegExp(pattern, 'iu').exec(answer.slice(stepOffset));
113
+ if (!match)
114
+ return false;
115
+ stepOffset += match.index + match[0].length;
116
+ return true;
117
+ });
118
+ const displayMathCount = (answer.match(/(?<!\\)\$\$/gu) || []).length;
119
+ const inlineMathCount = (answer.replace(/(?<!\\)\$\$/gu, '').match(/(?<!\\)\$/gu) || []).length;
120
+ const balancedMath = displayMathCount % 2 === 0 && inlineMathCount % 2 === 0;
121
+ const documents = new Set(entry.documents.map(document => document.documentId));
122
+ const invalidCitationIds = response.citations.filter(citation => !documents.has(citation.documentId)).map(citation => citation.citationId);
123
+ const passed = !missingFactIds.length && !unsupportedClaimIds.length && orderedStepsSatisfied && balancedMath
124
+ && !invalidCitationIds.length && conflictSignalled === entry.reference.expectsConflict && abstentionSignalled === entry.reference.expectsAbstention;
125
+ return {
126
+ caseId: entry.id, split: entry.split, language: entry.language, category: entry.category,
127
+ referenceFactCount: entry.reference.facts.length, coveredFactIds, missingFactIds,
128
+ unsupportedProbeCount: entry.reference.unsupportedClaims.length, unsupportedClaimIds,
129
+ conflictExpected: entry.reference.expectsConflict, conflictSignalled,
130
+ abstentionExpected: entry.reference.expectsAbstention, abstentionSignalled,
131
+ orderedStepsSatisfied, balancedMath, invalidCitationIds, passed,
132
+ };
133
+ }
134
+ function summarizeAnswerQuality(results) {
135
+ const count = (predicate) => results.filter(predicate).length;
136
+ const fraction = (numerator, denominator) => ({ numerator, denominator, rate: denominator ? numerator / denominator : null });
137
+ const facts = results.reduce((sum, row) => sum + row.referenceFactCount, 0);
138
+ const covered = results.reduce((sum, row) => sum + row.coveredFactIds.length, 0);
139
+ const probes = results.reduce((sum, row) => sum + row.unsupportedProbeCount, 0);
140
+ const unsupported = results.reduce((sum, row) => sum + row.unsupportedClaimIds.length, 0);
141
+ return {
142
+ cases: results.length,
143
+ referenceAcceptance: fraction(count(row => row.passed), results.length),
144
+ referenceFactCoverage: fraction(covered, facts),
145
+ unsupportedAssertionProbeHitRate: fraction(unsupported, probes),
146
+ falseConflictRate: fraction(count(row => !row.conflictExpected && row.conflictSignalled), count(row => !row.conflictExpected)),
147
+ missedConflictRate: fraction(count(row => row.conflictExpected && !row.conflictSignalled), count(row => row.conflictExpected)),
148
+ correctAbstentionRate: fraction(count(row => row.abstentionExpected && row.abstentionSignalled), count(row => row.abstentionExpected)),
149
+ unexpectedAbstentionRate: fraction(count(row => !row.abstentionExpected && row.abstentionSignalled), count(row => !row.abstentionExpected)),
150
+ unbalancedMathAnswers: count(row => !row.balancedMath),
151
+ outOfScopeCitations: results.reduce((sum, row) => sum + row.invalidCitationIds.length, 0),
152
+ };
153
+ }
@@ -0,0 +1,118 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const fs_1 = __importDefault(require("fs"));
7
+ const path_1 = __importDefault(require("path"));
8
+ const AnswerQualityEvaluation_1 = require("./AnswerQualityEvaluation");
9
+ const raw = JSON.parse(fs_1.default.readFileSync(path_1.default.resolve(__dirname, '../../fixtures/answer-quality/v1.json'), 'utf8'));
10
+ describe('independent answer-quality measurements', () => {
11
+ test('validates disjoint bilingual calibration/evaluation sets covering every declared category', () => {
12
+ const corpus = (0, AnswerQualityEvaluation_1.parseAnswerQualityCorpus)(raw);
13
+ expect(corpus.cases.filter(entry => entry.split === 'calibration')).toHaveLength(6);
14
+ const heldOut = corpus.cases.filter(entry => entry.split === 'evaluation');
15
+ expect(heldOut).toHaveLength(18);
16
+ for (const category of AnswerQualityEvaluation_1.ANSWER_QUALITY_CATEGORIES)
17
+ expect(heldOut.filter(entry => entry.category === category).map(entry => entry.language).sort()).toEqual(['en', 'zh']);
18
+ });
19
+ test('the confirmation corpus uses disjoint evaluation documents and subjects', () => {
20
+ const confirmation = (0, AnswerQualityEvaluation_1.parseAnswerQualityCorpus)(JSON.parse(fs_1.default.readFileSync(path_1.default.resolve(__dirname, '../../fixtures/answer-quality/v2.json'), 'utf8')));
21
+ const original = (0, AnswerQualityEvaluation_1.parseAnswerQualityCorpus)(raw);
22
+ const queries = new Set(original.cases.map(entry => entry.query));
23
+ const sourceContents = new Set(original.cases.flatMap(entry => entry.documents.map(document => document.content.replace(/\s+/g, ' ').trim())));
24
+ for (const entry of confirmation.cases.filter(item => item.split === 'evaluation')) {
25
+ expect(queries.has(entry.query)).toBe(false);
26
+ for (const document of entry.documents)
27
+ expect(sourceContents.has(document.content.replace(/\s+/g, ' ').trim())).toBe(false);
28
+ }
29
+ for (const category of AnswerQualityEvaluation_1.ANSWER_QUALITY_CATEGORIES)
30
+ expect(confirmation.cases.filter(entry => entry.split === 'evaluation' && entry.category === category).map(entry => entry.language).sort()).toEqual(['en', 'zh']);
31
+ });
32
+ test('rejects source leakage between calibration and evaluation', () => {
33
+ const corpus = structuredClone(raw);
34
+ corpus.cases[6].documents[0].content = corpus.cases[0].documents[0].content;
35
+ expect(() => (0, AnswerQualityEvaluation_1.parseAnswerQualityCorpus)(corpus)).toThrow('source leakage');
36
+ });
37
+ test('does not substitute runtime sufficient claims for independently labelled fact coverage', () => {
38
+ const entry = (0, AnswerQualityEvaluation_1.parseAnswerQualityCorpus)(raw).cases.find(item => item.id === 'eval-idempotency-en');
39
+ const response = { answer: 'It ensures exactly-once network delivery.', citations: [], answerReleaseReview: { decision: 'release' } };
40
+ const measurement = (0, AnswerQualityEvaluation_1.measureAnswerQuality)(entry, response);
41
+ expect(measurement.coveredFactIds).toEqual([]);
42
+ expect(measurement.unsupportedClaimIds).toEqual(['unsupported-1']);
43
+ expect(measurement.passed).toBe(false);
44
+ });
45
+ test.each([
46
+ 'A write conflict can cause a transaction to retry.',
47
+ 'Conflict serializability preserves an equivalent serial schedule.',
48
+ '键冲突需要额外的消解策略。',
49
+ '写写冲突可以用版本校验检测。',
50
+ 'There is no conflict between the source observations.',
51
+ 'There is no conflicting evidence.',
52
+ '来源之间没有冲突。',
53
+ ])('does not confuse a domain conflict or its negation with conflicting evidence: %s', answer => {
54
+ const entry = (0, AnswerQualityEvaluation_1.parseAnswerQualityCorpus)(raw).cases[0];
55
+ expect((0, AnswerQualityEvaluation_1.measureAnswerQuality)(entry, { answer, citations: [] }).conflictSignalled).toBe(false);
56
+ });
57
+ test.each([
58
+ 'The source observations conflict; the available evidence does not establish which is correct.',
59
+ 'The measurements disagree.',
60
+ 'The evidence is inconsistent.',
61
+ 'Conflicting evidence for the clock rate: 3 Hz and 8 Hz.',
62
+ '来源中的观测存在冲突,现有证据无法确定哪一项正确。',
63
+ '两份报告之间存在矛盾。',
64
+ ])('recognizes an explicit source disagreement: %s', answer => {
65
+ const entry = (0, AnswerQualityEvaluation_1.parseAnswerQualityCorpus)(raw).cases[0];
66
+ expect((0, AnswerQualityEvaluation_1.measureAnswerQuality)(entry, { answer, citations: [] }).conflictSignalled).toBe(true);
67
+ });
68
+ test('retains explicit denominators and reports undefined rates when no opportunities exist', () => {
69
+ const entry = (0, AnswerQualityEvaluation_1.parseAnswerQualityCorpus)(raw).cases.find(item => item.id === 'eval-missing-en');
70
+ const measurement = (0, AnswerQualityEvaluation_1.measureAnswerQuality)(entry, { answer: 'Insufficient evidence.', citations: [], answerReleaseReview: { decision: 'abstain' } });
71
+ const summary = (0, AnswerQualityEvaluation_1.summarizeAnswerQuality)([measurement]);
72
+ expect(summary.referenceFactCoverage).toEqual({ numerator: 0, denominator: 0, rate: null });
73
+ expect(summary.correctAbstentionRate).toEqual({ numerator: 1, denominator: 1, rate: 1 });
74
+ expect(summary.missedConflictRate.rate).toBeNull();
75
+ });
76
+ test.each([
77
+ 'The archive does not provide a measured melting point for the sample.',
78
+ 'The notes contain no measurements of the sample temperature.',
79
+ 'The requested measurement has not been recorded in the available sources.',
80
+ 'I cannot give a grounded answer from these notes.',
81
+ '星云合金记录 存档没有提供星云合金熔点的测量数据。',
82
+ '现有资料未记录这个样品的测量值。',
83
+ '笔记中没有该参数的测量结果。',
84
+ '当前资料不足以确定这个参数的数值。',
85
+ '我暂时不能对“什么是热预算,它有什么用途?”给出有依据的回答。',
86
+ ])('recognizes an evidence-based unknown answer independently of its release label: %s', answer => {
87
+ const entry = (0, AnswerQualityEvaluation_1.parseAnswerQualityCorpus)(raw).cases.find(item => item.id === 'eval-missing-en');
88
+ const measurement = (0, AnswerQualityEvaluation_1.measureAnswerQuality)(entry, { answer, citations: [], answerReleaseReview: { decision: 'release' } });
89
+ expect(measurement.abstentionSignalled).toBe(true);
90
+ });
91
+ test.each([
92
+ 'The journal ensures there is no data loss after acknowledgement.',
93
+ 'The source does not report data loss during the experiment.',
94
+ 'The database does not provide serializable isolation.',
95
+ 'The measured signal is not 12 Hz; it is 18 Hz.',
96
+ 'The archive reports no conflict between these measurements.',
97
+ '日志确保确认后没有数据丢失。',
98
+ '资料没有记录任何数据丢失。',
99
+ '定标频率不是12赫兹,而是18赫兹。',
100
+ '实验报告中没有数据泄漏。',
101
+ ])('does not label a factual negation as an unknown answer: %s', answer => {
102
+ const entry = (0, AnswerQualityEvaluation_1.parseAnswerQualityCorpus)(raw).cases.find(item => item.id === 'eval-missing-en');
103
+ const measurement = (0, AnswerQualityEvaluation_1.measureAnswerQuality)(entry, { answer, citations: [] });
104
+ expect(measurement.abstentionSignalled).toBe(false);
105
+ });
106
+ test('does not use an internal abstain label to claim that the public answer discloses uncertainty', () => {
107
+ const entry = (0, AnswerQualityEvaluation_1.parseAnswerQualityCorpus)(raw).cases.find(item => item.id === 'eval-missing-en');
108
+ const measurement = (0, AnswerQualityEvaluation_1.measureAnswerQuality)(entry, { answer: 'The melting point is 900 K.', citations: [], answerReleaseReview: { decision: 'abstain' } });
109
+ expect(measurement.abstentionSignalled).toBe(false);
110
+ });
111
+ test('catches reversed procedural steps and unbalanced math', () => {
112
+ const entry = (0, AnswerQualityEvaluation_1.parseAnswerQualityCorpus)(raw).cases.find(item => item.id === 'eval-replacement-en');
113
+ const response = { answer: 'Acknowledge then rename, flush the temporary file. $R_1', citations: [] };
114
+ const measurement = (0, AnswerQualityEvaluation_1.measureAnswerQuality)(entry, response);
115
+ expect(measurement.orderedStepsSatisfied).toBe(false);
116
+ expect(measurement.balancedMath).toBe(false);
117
+ });
118
+ });