@elite-dangerous-almanac/core 0.1.0-beta.1

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 (357) hide show
  1. package/LICENSE +48 -0
  2. package/PROVENANCE/SNAPSHOTS.md +36 -0
  3. package/PROVENANCE/astro/SOURCES.md +94 -0
  4. package/PROVENANCE/commodities/SOURCES.md +41 -0
  5. package/PROVENANCE/materials/SOURCES.md +69 -0
  6. package/PROVENANCE/ships/SOURCES.md +1580 -0
  7. package/README.md +148 -0
  8. package/THIRD_PARTY_NOTICES.md +202 -0
  9. package/dist/astro/codex-region-lookup.d.ts +169 -0
  10. package/dist/astro/codex-region-lookup.js +1 -0
  11. package/dist/astro/codex-region-lookup.js.map +1 -0
  12. package/dist/astro/codex-region.d.ts +149 -0
  13. package/dist/astro/codex-region.js +1 -0
  14. package/dist/astro/codex-region.js.map +1 -0
  15. package/dist/astro/galaxy-grid.d.ts +83 -0
  16. package/dist/astro/galaxy-grid.js +1 -0
  17. package/dist/astro/galaxy-grid.js.map +1 -0
  18. package/dist/astro/hand-authored-regions.d.ts +121 -0
  19. package/dist/astro/hand-authored-regions.js +1 -0
  20. package/dist/astro/hand-authored-regions.js.map +1 -0
  21. package/dist/astro/index.d.ts +140 -0
  22. package/dist/astro/index.js +1 -0
  23. package/dist/astro/index.js.map +1 -0
  24. package/dist/astro/mass-code.d.ts +55 -0
  25. package/dist/astro/mass-code.js +1 -0
  26. package/dist/astro/mass-code.js.map +1 -0
  27. package/dist/astro/naming-region-origins.d.ts +4 -0
  28. package/dist/astro/naming-region-origins.js +1 -0
  29. package/dist/astro/naming-region-origins.js.map +1 -0
  30. package/dist/astro/nebulae-all.d.ts +40 -0
  31. package/dist/astro/nebulae-all.js +1 -0
  32. package/dist/astro/nebulae-all.js.map +1 -0
  33. package/dist/astro/nebulae-planetary.d.ts +37 -0
  34. package/dist/astro/nebulae-planetary.js +1 -0
  35. package/dist/astro/nebulae-planetary.js.map +1 -0
  36. package/dist/astro/nebulae-procgen.d.ts +36 -0
  37. package/dist/astro/nebulae-procgen.js +1 -0
  38. package/dist/astro/nebulae-procgen.js.map +1 -0
  39. package/dist/astro/nebulae-real.d.ts +37 -0
  40. package/dist/astro/nebulae-real.js +1 -0
  41. package/dist/astro/nebulae-real.js.map +1 -0
  42. package/dist/astro/nebulae.d.ts +169 -0
  43. package/dist/astro/nebulae.js +1 -0
  44. package/dist/astro/nebulae.js.map +1 -0
  45. package/dist/astro/permit-locked-regions.d.ts +54 -0
  46. package/dist/astro/permit-locked-regions.js +1 -0
  47. package/dist/astro/permit-locked-regions.js.map +1 -0
  48. package/dist/astro/permit-locked-systems.d.ts +74 -0
  49. package/dist/astro/permit-locked-systems.js +1 -0
  50. package/dist/astro/permit-locked-systems.js.map +1 -0
  51. package/dist/astro/permit-locks.d.ts +130 -0
  52. package/dist/astro/permit-locks.js +1 -0
  53. package/dist/astro/permit-locks.js.map +1 -0
  54. package/dist/astro/procedural-system.d.ts +228 -0
  55. package/dist/astro/procedural-system.js +1 -0
  56. package/dist/astro/procedural-system.js.map +1 -0
  57. package/dist/astro/sector-name.d.ts +87 -0
  58. package/dist/astro/sector-name.js +1 -0
  59. package/dist/astro/sector-name.js.map +1 -0
  60. package/dist/astro/system-address-input.d.ts +76 -0
  61. package/dist/astro/system-address-input.js +1 -0
  62. package/dist/astro/system-address-input.js.map +1 -0
  63. package/dist/astro/system-address.d.ts +4 -0
  64. package/dist/astro/system-address.js +1 -0
  65. package/dist/astro/system-address.js.map +1 -0
  66. package/dist/astro/system-name.d.ts +187 -0
  67. package/dist/astro/system-name.js +1 -0
  68. package/dist/astro/system-name.js.map +1 -0
  69. package/dist/chunk-2FHHMYDC.js +1 -0
  70. package/dist/chunk-2FHHMYDC.js.map +1 -0
  71. package/dist/chunk-462OKHXR.js +1 -0
  72. package/dist/chunk-462OKHXR.js.map +1 -0
  73. package/dist/chunk-5H74FKY7.js +1 -0
  74. package/dist/chunk-5H74FKY7.js.map +1 -0
  75. package/dist/chunk-6LUEKHO5.js +1 -0
  76. package/dist/chunk-6LUEKHO5.js.map +1 -0
  77. package/dist/chunk-76XKY2Y2.js +1 -0
  78. package/dist/chunk-76XKY2Y2.js.map +1 -0
  79. package/dist/chunk-7EE5VIHR.js +1 -0
  80. package/dist/chunk-7EE5VIHR.js.map +1 -0
  81. package/dist/chunk-A3NM7SAJ.js +1 -0
  82. package/dist/chunk-A3NM7SAJ.js.map +1 -0
  83. package/dist/chunk-A6XPYSVR.js +1 -0
  84. package/dist/chunk-A6XPYSVR.js.map +1 -0
  85. package/dist/chunk-AA3K5XUE.js +1 -0
  86. package/dist/chunk-AA3K5XUE.js.map +1 -0
  87. package/dist/chunk-AVZI6VKA.js +1 -0
  88. package/dist/chunk-AVZI6VKA.js.map +1 -0
  89. package/dist/chunk-B5TT26XE.js +1 -0
  90. package/dist/chunk-B5TT26XE.js.map +1 -0
  91. package/dist/chunk-BNILZXJD.js +1 -0
  92. package/dist/chunk-BNILZXJD.js.map +1 -0
  93. package/dist/chunk-BRDQUJXV.js +1 -0
  94. package/dist/chunk-BRDQUJXV.js.map +1 -0
  95. package/dist/chunk-BTPV5CIF.js +1 -0
  96. package/dist/chunk-BTPV5CIF.js.map +1 -0
  97. package/dist/chunk-CI3ACMRA.js +1 -0
  98. package/dist/chunk-CI3ACMRA.js.map +1 -0
  99. package/dist/chunk-COE5ADYJ.js +1 -0
  100. package/dist/chunk-COE5ADYJ.js.map +1 -0
  101. package/dist/chunk-CWAX3BSH.js +1 -0
  102. package/dist/chunk-CWAX3BSH.js.map +1 -0
  103. package/dist/chunk-DACZE3HX.js +1 -0
  104. package/dist/chunk-DACZE3HX.js.map +1 -0
  105. package/dist/chunk-DURKO7JU.js +1 -0
  106. package/dist/chunk-DURKO7JU.js.map +1 -0
  107. package/dist/chunk-E45EDCYH.js +1 -0
  108. package/dist/chunk-E45EDCYH.js.map +1 -0
  109. package/dist/chunk-ELIZXUMI.js +1 -0
  110. package/dist/chunk-ELIZXUMI.js.map +1 -0
  111. package/dist/chunk-EYGVDJ2I.js +1 -0
  112. package/dist/chunk-EYGVDJ2I.js.map +1 -0
  113. package/dist/chunk-FGXWVFN6.js +1 -0
  114. package/dist/chunk-FGXWVFN6.js.map +1 -0
  115. package/dist/chunk-GJCB2Z72.js +1 -0
  116. package/dist/chunk-GJCB2Z72.js.map +1 -0
  117. package/dist/chunk-HI7FCS3G.js +1 -0
  118. package/dist/chunk-HI7FCS3G.js.map +1 -0
  119. package/dist/chunk-HKXXFIRI.js +1 -0
  120. package/dist/chunk-HKXXFIRI.js.map +1 -0
  121. package/dist/chunk-HTB52N6S.js +1 -0
  122. package/dist/chunk-HTB52N6S.js.map +1 -0
  123. package/dist/chunk-I7PIDRMU.js +1 -0
  124. package/dist/chunk-I7PIDRMU.js.map +1 -0
  125. package/dist/chunk-IH4NXKVW.js +1 -0
  126. package/dist/chunk-IH4NXKVW.js.map +1 -0
  127. package/dist/chunk-INNFH37U.js +1 -0
  128. package/dist/chunk-INNFH37U.js.map +1 -0
  129. package/dist/chunk-J2PNZQY4.js +1 -0
  130. package/dist/chunk-J2PNZQY4.js.map +1 -0
  131. package/dist/chunk-JQG4C67D.js +1 -0
  132. package/dist/chunk-JQG4C67D.js.map +1 -0
  133. package/dist/chunk-JTQVWIGL.js +1 -0
  134. package/dist/chunk-JTQVWIGL.js.map +1 -0
  135. package/dist/chunk-JWJ7RSZC.js +1 -0
  136. package/dist/chunk-JWJ7RSZC.js.map +1 -0
  137. package/dist/chunk-K3AMV27L.js +1 -0
  138. package/dist/chunk-K3AMV27L.js.map +1 -0
  139. package/dist/chunk-K7F6WC4T.js +1 -0
  140. package/dist/chunk-K7F6WC4T.js.map +1 -0
  141. package/dist/chunk-K7L7SMIR.js +1 -0
  142. package/dist/chunk-K7L7SMIR.js.map +1 -0
  143. package/dist/chunk-KG4EWDZZ.js +1 -0
  144. package/dist/chunk-KG4EWDZZ.js.map +1 -0
  145. package/dist/chunk-KMFUCORC.js +1 -0
  146. package/dist/chunk-KMFUCORC.js.map +1 -0
  147. package/dist/chunk-L2ZZXEZM.js +1 -0
  148. package/dist/chunk-L2ZZXEZM.js.map +1 -0
  149. package/dist/chunk-L747RVPO.js +1 -0
  150. package/dist/chunk-L747RVPO.js.map +1 -0
  151. package/dist/chunk-MFV4VZFP.js +1 -0
  152. package/dist/chunk-MFV4VZFP.js.map +1 -0
  153. package/dist/chunk-NWPK6Q3S.js +1 -0
  154. package/dist/chunk-NWPK6Q3S.js.map +1 -0
  155. package/dist/chunk-PMJG7PHU.js +1 -0
  156. package/dist/chunk-PMJG7PHU.js.map +1 -0
  157. package/dist/chunk-PP2VSA6M.js +1 -0
  158. package/dist/chunk-PP2VSA6M.js.map +1 -0
  159. package/dist/chunk-Q22LXT53.js +1 -0
  160. package/dist/chunk-Q22LXT53.js.map +1 -0
  161. package/dist/chunk-Q5MR36RW.js +1 -0
  162. package/dist/chunk-Q5MR36RW.js.map +1 -0
  163. package/dist/chunk-Q5XOGATC.js +1 -0
  164. package/dist/chunk-Q5XOGATC.js.map +1 -0
  165. package/dist/chunk-QTDBO7R2.js +1 -0
  166. package/dist/chunk-QTDBO7R2.js.map +1 -0
  167. package/dist/chunk-R4OD62HV.js +1 -0
  168. package/dist/chunk-R4OD62HV.js.map +1 -0
  169. package/dist/chunk-RD73TFGS.js +1 -0
  170. package/dist/chunk-RD73TFGS.js.map +1 -0
  171. package/dist/chunk-RIT6MOO5.js +1 -0
  172. package/dist/chunk-RIT6MOO5.js.map +1 -0
  173. package/dist/chunk-RVSXKQHE.js +1 -0
  174. package/dist/chunk-RVSXKQHE.js.map +1 -0
  175. package/dist/chunk-S4DBNX2B.js +1 -0
  176. package/dist/chunk-S4DBNX2B.js.map +1 -0
  177. package/dist/chunk-S4UWCHL6.js +1 -0
  178. package/dist/chunk-S4UWCHL6.js.map +1 -0
  179. package/dist/chunk-SQS7672E.js +1 -0
  180. package/dist/chunk-SQS7672E.js.map +1 -0
  181. package/dist/chunk-TLNHETGC.js +1 -0
  182. package/dist/chunk-TLNHETGC.js.map +1 -0
  183. package/dist/chunk-U6TMCYA6.js +1 -0
  184. package/dist/chunk-U6TMCYA6.js.map +1 -0
  185. package/dist/chunk-V4C6FIE2.js +1 -0
  186. package/dist/chunk-V4C6FIE2.js.map +1 -0
  187. package/dist/chunk-VXVUEF5U.js +1 -0
  188. package/dist/chunk-VXVUEF5U.js.map +1 -0
  189. package/dist/chunk-VZXL5KBR.js +1 -0
  190. package/dist/chunk-VZXL5KBR.js.map +1 -0
  191. package/dist/chunk-VZZ2XIRE.js +1 -0
  192. package/dist/chunk-VZZ2XIRE.js.map +1 -0
  193. package/dist/chunk-WV5YM7H5.js +1 -0
  194. package/dist/chunk-WV5YM7H5.js.map +1 -0
  195. package/dist/chunk-Y2MUIE5W.js +1 -0
  196. package/dist/chunk-Y2MUIE5W.js.map +1 -0
  197. package/dist/chunk-Z43DN4PY.js +1 -0
  198. package/dist/chunk-Z43DN4PY.js.map +1 -0
  199. package/dist/chunk-Z4GTTB7I.js +1 -0
  200. package/dist/chunk-Z4GTTB7I.js.map +1 -0
  201. package/dist/chunk-Z4OUB4SJ.js +1 -0
  202. package/dist/chunk-Z4OUB4SJ.js.map +1 -0
  203. package/dist/chunk-ZFT56QFR.js +1 -0
  204. package/dist/chunk-ZFT56QFR.js.map +1 -0
  205. package/dist/chunk-ZNCXENNB.js +1 -0
  206. package/dist/chunk-ZNCXENNB.js.map +1 -0
  207. package/dist/commodities/commodities-all.d.ts +25 -0
  208. package/dist/commodities/commodities-all.js +1 -0
  209. package/dist/commodities/commodities-all.js.map +1 -0
  210. package/dist/commodities/commodities-rare.d.ts +34 -0
  211. package/dist/commodities/commodities-rare.js +1 -0
  212. package/dist/commodities/commodities-rare.js.map +1 -0
  213. package/dist/commodities/commodities-standard.d.ts +34 -0
  214. package/dist/commodities/commodities-standard.js +1 -0
  215. package/dist/commodities/commodities-standard.js.map +1 -0
  216. package/dist/commodities/commodities.d.ts +142 -0
  217. package/dist/commodities/commodities.js +1 -0
  218. package/dist/commodities/commodities.js.map +1 -0
  219. package/dist/commodities/index.d.ts +30 -0
  220. package/dist/commodities/index.js +1 -0
  221. package/dist/commodities/index.js.map +1 -0
  222. package/dist/galactic-position-shLkm4Qg.d.ts +30 -0
  223. package/dist/materials/index.d.ts +47 -0
  224. package/dist/materials/index.js +1 -0
  225. package/dist/materials/index.js.map +1 -0
  226. package/dist/materials/materials-all.d.ts +26 -0
  227. package/dist/materials/materials-all.js +1 -0
  228. package/dist/materials/materials-all.js.map +1 -0
  229. package/dist/materials/materials-encoded.d.ts +31 -0
  230. package/dist/materials/materials-encoded.js +1 -0
  231. package/dist/materials/materials-encoded.js.map +1 -0
  232. package/dist/materials/materials-manufactured.d.ts +32 -0
  233. package/dist/materials/materials-manufactured.js +1 -0
  234. package/dist/materials/materials-manufactured.js.map +1 -0
  235. package/dist/materials/materials-raw.d.ts +31 -0
  236. package/dist/materials/materials-raw.js +1 -0
  237. package/dist/materials/materials-raw.js.map +1 -0
  238. package/dist/materials/materials.d.ts +277 -0
  239. package/dist/materials/materials.js +1 -0
  240. package/dist/materials/materials.js.map +1 -0
  241. package/dist/materials/micro-resources-all.d.ts +28 -0
  242. package/dist/materials/micro-resources-all.js +1 -0
  243. package/dist/materials/micro-resources-all.js.map +1 -0
  244. package/dist/materials/micro-resources-component.d.ts +29 -0
  245. package/dist/materials/micro-resources-component.js +1 -0
  246. package/dist/materials/micro-resources-component.js.map +1 -0
  247. package/dist/materials/micro-resources-consumable.d.ts +29 -0
  248. package/dist/materials/micro-resources-consumable.js +1 -0
  249. package/dist/materials/micro-resources-consumable.js.map +1 -0
  250. package/dist/materials/micro-resources-data.d.ts +29 -0
  251. package/dist/materials/micro-resources-data.js +1 -0
  252. package/dist/materials/micro-resources-data.js.map +1 -0
  253. package/dist/materials/micro-resources-item.d.ts +29 -0
  254. package/dist/materials/micro-resources-item.js +1 -0
  255. package/dist/materials/micro-resources-item.js.map +1 -0
  256. package/dist/materials/micro-resources.d.ts +136 -0
  257. package/dist/materials/micro-resources.js +1 -0
  258. package/dist/materials/micro-resources.js.map +1 -0
  259. package/dist/ship-loadout-Ba63RDf-.d.ts +1059 -0
  260. package/dist/ships/ammunition.d.ts +107 -0
  261. package/dist/ships/ammunition.js +1 -0
  262. package/dist/ships/ammunition.js.map +1 -0
  263. package/dist/ships/armour.d.ts +134 -0
  264. package/dist/ships/armour.js +1 -0
  265. package/dist/ships/armour.js.map +1 -0
  266. package/dist/ships/blueprint-costs.d.ts +128 -0
  267. package/dist/ships/blueprint-costs.js +1 -0
  268. package/dist/ships/blueprint-costs.js.map +1 -0
  269. package/dist/ships/blueprint-journal.d.ts +116 -0
  270. package/dist/ships/blueprint-journal.js +1 -0
  271. package/dist/ships/blueprint-journal.js.map +1 -0
  272. package/dist/ships/blueprints.d.ts +103 -0
  273. package/dist/ships/blueprints.js +1 -0
  274. package/dist/ships/blueprints.js.map +1 -0
  275. package/dist/ships/decorative-modifications.d.ts +176 -0
  276. package/dist/ships/decorative-modifications.js +1 -0
  277. package/dist/ships/decorative-modifications.js.map +1 -0
  278. package/dist/ships/engineering-options.d.ts +246 -0
  279. package/dist/ships/engineering-options.js +1 -0
  280. package/dist/ships/engineering-options.js.map +1 -0
  281. package/dist/ships/engineering.d.ts +229 -0
  282. package/dist/ships/engineering.js +1 -0
  283. package/dist/ships/engineering.js.map +1 -0
  284. package/dist/ships/experimental-effect-costs.d.ts +56 -0
  285. package/dist/ships/experimental-effect-costs.js +1 -0
  286. package/dist/ships/experimental-effect-costs.js.map +1 -0
  287. package/dist/ships/experimental-effects.d.ts +62 -0
  288. package/dist/ships/experimental-effects.js +1 -0
  289. package/dist/ships/experimental-effects.js.map +1 -0
  290. package/dist/ships/index.d.ts +205 -0
  291. package/dist/ships/index.js +1 -0
  292. package/dist/ships/index.js.map +1 -0
  293. package/dist/ships/jump-range.d.ts +115 -0
  294. package/dist/ships/jump-range.js +1 -0
  295. package/dist/ships/jump-range.js.map +1 -0
  296. package/dist/ships/loadout-calculations.d.ts +109 -0
  297. package/dist/ships/loadout-calculations.js +1 -0
  298. package/dist/ships/loadout-calculations.js.map +1 -0
  299. package/dist/ships/loadout-validation.d.ts +80 -0
  300. package/dist/ships/loadout-validation.js +1 -0
  301. package/dist/ships/loadout-validation.js.map +1 -0
  302. package/dist/ships/module-capabilities.d.ts +205 -0
  303. package/dist/ships/module-capabilities.js +1 -0
  304. package/dist/ships/module-capabilities.js.map +1 -0
  305. package/dist/ships/modules-all.d.ts +43 -0
  306. package/dist/ships/modules-all.js +1 -0
  307. package/dist/ships/modules-all.js.map +1 -0
  308. package/dist/ships/modules-core.d.ts +40 -0
  309. package/dist/ships/modules-core.js +1 -0
  310. package/dist/ships/modules-core.js.map +1 -0
  311. package/dist/ships/modules-hardpoint.d.ts +42 -0
  312. package/dist/ships/modules-hardpoint.js +1 -0
  313. package/dist/ships/modules-hardpoint.js.map +1 -0
  314. package/dist/ships/modules-internal.d.ts +40 -0
  315. package/dist/ships/modules-internal.js +1 -0
  316. package/dist/ships/modules-internal.js.map +1 -0
  317. package/dist/ships/modules-utility.d.ts +40 -0
  318. package/dist/ships/modules-utility.js +1 -0
  319. package/dist/ships/modules-utility.js.map +1 -0
  320. package/dist/ships/modules.d.ts +755 -0
  321. package/dist/ships/modules.js +1 -0
  322. package/dist/ships/modules.js.map +1 -0
  323. package/dist/ships/power.d.ts +168 -0
  324. package/dist/ships/power.js +1 -0
  325. package/dist/ships/power.js.map +1 -0
  326. package/dist/ships/pre-engineered-stats.d.ts +147 -0
  327. package/dist/ships/pre-engineered-stats.js +1 -0
  328. package/dist/ships/pre-engineered-stats.js.map +1 -0
  329. package/dist/ships/pre-engineered.d.ts +215 -0
  330. package/dist/ships/pre-engineered.js +1 -0
  331. package/dist/ships/pre-engineered.js.map +1 -0
  332. package/dist/ships/resistances.d.ts +208 -0
  333. package/dist/ships/resistances.js +1 -0
  334. package/dist/ships/resistances.js.map +1 -0
  335. package/dist/ships/shields.d.ts +221 -0
  336. package/dist/ships/shields.js +1 -0
  337. package/dist/ships/shields.js.map +1 -0
  338. package/dist/ships/ship-loadout.d.ts +16 -0
  339. package/dist/ships/ship-loadout.js +1 -0
  340. package/dist/ships/ship-loadout.js.map +1 -0
  341. package/dist/ships/ships.d.ts +191 -0
  342. package/dist/ships/ships.js +1 -0
  343. package/dist/ships/ships.js.map +1 -0
  344. package/dist/ships/slef.d.ts +318 -0
  345. package/dist/ships/slef.js +1 -0
  346. package/dist/ships/slef.js.map +1 -0
  347. package/dist/ships/slots.d.ts +418 -0
  348. package/dist/ships/slots.js +1 -0
  349. package/dist/ships/slots.js.map +1 -0
  350. package/dist/ships/source-purchase.d.ts +132 -0
  351. package/dist/ships/source-purchase.js +1 -0
  352. package/dist/ships/source-purchase.js.map +1 -0
  353. package/dist/ships/weapons.d.ts +380 -0
  354. package/dist/ships/weapons.js +1 -0
  355. package/dist/ships/weapons.js.map +1 -0
  356. package/dist/system-address-DYsN1qOT.d.ts +313 -0
  357. package/package.json +375 -0
@@ -0,0 +1,1580 @@
1
+ # Data sources — `data/ships/`
2
+
3
+ ## Upstream snapshots this domain is pinned to
4
+
5
+ Referred to throughout by source name; the pin is here, once.
6
+
7
+ | Source | Pin | Acquired |
8
+ | ----------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------- |
9
+ | EDCD FDevIDs — `shipyard.csv`, `outfitting.csv` | no immutable revision recorded | 2026-07-24 UTC |
10
+ | EDCD/coriolis-data — `ships/*.json`, `modules/**`, `modifications/*` | commit `0db9234b5b9ce8c939ea84133d7ce336eea88e27` | 2026-07-24 UTC |
11
+ | coriolis-data `modifications/modules.json` | SHA-256 `09b6427c86bc3cfb578a246f7c6be1791429bb67009b7adaa7909e30aadc160f` — read from the branch tip, so pinned by digest | 2026-08-05 UTC |
12
+ | EDSY `eddb.js` | commit `cd68edfba665719958ce038b6e5d9eb02d0d2b02`, SHA-256 `967834d65a75ab1dea4bbaa7e1d6674cbe4083dca03f770d058497e9f7693071`, internal `db 20260428` / `version 423039901` | 2026-08-02 UTC |
13
+ | EDSY `eddb.js` — Vessel Hangar variants | commit `510468167e0ef3b895e39391a8c56b5cdd5c3282`, SHA-256 `0574db06f796cdf7dfbe20a5f89f8a378e692873ae49133e9b49557fe8d8cba3` | 2026-08-09 UTC |
14
+ | EDSY `edsy.js` | SHA-256 `a40e9bbe65d482a029527d6dc2abdbd1819672e5a5d4a3a4d88ea411f02575f5` — read from the branch tip, so pinned by digest | 2026-08-06 UTC |
15
+ | Odyssey Materials Helper CAPI fixture `application/src/test/resources/parser/capifc/test9.json` | commit `2c652a2349b754f1dde1a58b6daaac5a04e421a6` | 2026-08-09 UTC |
16
+ | EDCD/Coriolis — the application, for its formulas | commit `68c042ca6e3db62372cbbb2077cf972345511712` | 2026-08-01 UTC |
17
+ | msarilar/EDEngineer `EDEngineer/Resources/Data/blueprints.json` | SHA-256 `787e6bd0579264d7b4615a281318792cb212285786f4ae07f61ec1cc464cdec0` — read from the branch tip, so pinned by digest | 2026-08-08 UTC |
18
+ | Elite Dangerous in-game verification | observed in-game | 2026-08-12 UTC |
19
+
20
+ Every `eddb.js` derivation uses the baseline snapshot unless its catalogue note names
21
+ the Vessel Hangar snapshot.
22
+
23
+ **Some values come from no registry at all** — readings taken from the live game's own
24
+ outfitting, module and engineering panels, and captures contributed by the repository
25
+ owner from their own fleet. Each is named where it is used because it cannot be
26
+ re-derived from a public source.
27
+
28
+ ## Ships
29
+
30
+ Each hull is **one record** carrying its identity, its stats, and its slot layout —
31
+ identity from FDevIDs, stats and slots from coriolis-data, joined on `symbol`.
32
+
33
+ - **File:** `ships.jsonc` (48 player-flyable hulls).
34
+ - **Identity source:** FDevIDs `shipyard.csv`, columns `id,symbol,name,entitlement`.
35
+ - **Identity derivation:** records are carried over in shipyard order (roughly the
36
+ order hulls were introduced): internal `symbol` and display `name`. The CSV's
37
+ numeric ship-type `id` column is dropped — hulls are keyed by `symbol`.
38
+ `entitlement` is FDevIDs' DLC/grant token, kept only where the CSV gives one (28 of
39
+ the 48 hulls carry no entitlement, so the field is omitted rather than stored empty).
40
+ - **Stats + slots source:** coriolis-data `ships/*.json` — `properties` for stats,
41
+ `slots` + `bulkheads` for the layout.
42
+ - **Stats derivation:** acquisition normalization looks up each hull's coriolis
43
+ record by display name (normalized; coriolis "Viper" ⇒ registry "Viper MkIII") and
44
+ copies a fixed whitelist of `properties` fields (`hullMass`, `speed`, `boost`,
45
+ `baseArmour`, …). The repository's
46
+ `scripts/data/ships/merge-normalized-catalogues.mjs` then performs the deterministic
47
+ symbol join, preserving registry order and rejecting duplicate or unmatched input.
48
+ Masses are tonnes, speeds m/s, rotation rates deg/s.
49
+ - **Slots derivation:** coriolis's fixed-order `slots.standard` seven-array becomes
50
+ the seven named `core` sizes (power plant, thrusters, frame shift drive, life
51
+ support, power distributor, sensors, fuel tank); `slots.hardpoints` splits into
52
+ `hardpoints` (the non-zero weapon mounts) and `utility` (the count of zero
53
+ entries); `slots.internal` becomes `optional`. Both `hardpoints` and `optional` are
54
+ arrays of `{ size, restriction?, name? }` — the two fields below. Coriolis's per-hull
55
+ `bulkheads` are **not** kept on the hull: they are joined onto that hull's armour
56
+ modules instead (see "Modules"), because armour is a module and the catalogue keeps a
57
+ module's stats with the module. Slot keys follow the journal vocabulary
58
+ (`FrameShiftDrive`, `HugeHardpoint1`, `TinyHardpoint2`, `Slot01_Size6`, `Military01`,
59
+ `PlanetaryApproachSuite`).
60
+
61
+ ### `restriction` — a mount that takes one family of modules
62
+
63
+ Seven values: `mining` on a hardpoint, and `military`, `planetaryApproachSuite`,
64
+ `cargo`, `limpetController`, `vesselHangar` or `passenger` on an optional. Those seven
65
+ are the complete set the game has, not a subset these layouts happen to reach: there
66
+ are no mount-type restrictions on hardpoints (fixed/gimballed/turret) and no restricted
67
+ utility mounts, so neither has a value here and neither is a gap.
68
+
69
+ **Both registries carry the rule, and they agree mount-for-mount.**
70
+
71
+ - **coriolis-data** writes a restricted mount as an object rather than a bare size:
72
+ `ships/type_11_prospector.json` has `{ "class": 3, "name": "Mining", "eligible": {
73
+ "abl": 1, "ml": 1, "mvr": 1, "pwa": 1, "scl": 1, "sdm": 1 } }` for the large mount and
74
+ `{ "class": 5, "name": "Limpets", … }` / `{ "class": 5, "name": "Fighter", "eligible":
75
+ { "fh": 1 } }` for two of its optionals, and `ships/panther_clipper.json` the same
76
+ `"name": "Cargo"` object with `"eligible": { "cr": 1, "crl": 1, "ft": 1 }` on its
77
+ first size-8 mount and on its first size-**7** — not on the two size-8s.
78
+ - **EDSY** `eddb.js` carries it as a per-slot `reserved` map — `{hmtl:1,hmtm:1}` on the
79
+ Type-11's mounts 0, 1, 2 and 4, `{iclc,idlc,iftlc,ihblc,imlc,iplc,inlc,irlc,islc}` and
80
+ `{ifh:1}` on its two restricted optionals, `{cft:1,icr:1}` on the Panther's two, and
81
+ `{ipc:1}` on the Lynx Highliner's three cabin mounts.
82
+
83
+ They differ on exactly one entry: coriolis lists `pwa` (the Pulse Wave Analyser) as
84
+ eligible for a mining hardpoint. It is a **utility** fitting in both registries and in
85
+ this catalogue, and no utility module fits a hardpoint of any kind, so the difference is
86
+ a grouping artefact and is not stored. Coriolis's `sdm` group and EDSY's `hmtm` both
87
+ include the Sub-Surface Extraction Missile (`Hpt_Human_Extraction_Fixed_Medium`)
88
+ alongside the displacement missile it varies, so it counts as a mining tool despite its
89
+ unrelated symbol.
90
+
91
+ **`passenger` rests on a capture as well as on EDSY**, and needs to. `PASSENGER` is the
92
+ one restricted family absent from EDSY's journal import map and its `ipc` eligibility
93
+ check is commented out in `edsy.js`, so the reservation alone confirmed no journal
94
+ spelling. `fixtures/ships/slef-inara-lynx-highliner.jsonc` settles it: its `passenger01`,
95
+ `passenger02` and `passenger03` each hold an `int_mkii_passengercabin_*`, spelled
96
+ exactly as the stored names give them. The Lynx's `Slot02_Size5` follows the three cabin
97
+ mounts in the same capture.
98
+
99
+ ### `name` — the journal's own key for a mount
100
+
101
+ Thirteen hulls carry explicit journal slot names from EDSY. Ten depart from the game's
102
+ regular numbering; the Panther Clipper Mk II, Type-11 Prospector and Lynx Highliner are
103
+ included because EDSY publishes their otherwise-regular names. Non-derivable names are
104
+ stored on the mount, for example `{ "size": 1, "name": "Slot14_Size1" }`.
105
+
106
+ **Source:** EDSY `eddb.js` `ship[…].slotnames`. These are **journal** names rather than
107
+ EDSY's own — `edsy.js` reads them in `Build.fromJournal()` and writes them in
108
+ `exportJournal()`. Only EDSY carries them; coriolis-data does not model journal slot
109
+ names at all, so the corroborating source has to be captures, and five are in hand —
110
+ four SLEF exports and one journal — covering four of the 13 hulls with names of their
111
+ own (below). One is a journal rather
112
+ than an export: `journal-lynx-highliner.jsonc` gives Frontier's own casing for a hull the
113
+ Inara export already covers in lower case, and one thing that export does not — its
114
+ `PlanetaryApproachSuite` mount. All 29 outfitting keys bind to the stored layout; its
115
+ seven cosmetic slots (`WeaponColour`, `Decal1`–`3`, `EngineColour`, `VesselVoice`,
116
+ `ShipCockpit`) are not outfitting mounts and remain outside the export-only sweep.
117
+
118
+ **Derivation.** EDSY keeps `military` mounts in a group of their own and does not model
119
+ the planetary approach suite; this catalogue keeps both inline in `optional`. The two
120
+ lists are therefore walked in parallel: every mount consumes the next EDSY name except a
121
+ `military` one (which takes `Military01`, `Military02`) and the `planetaryApproachSuite`
122
+ one. EDSY's `slots` sizes equal this catalogue's mount-for-mount, and its name list is
123
+ exactly consumed. This is a naming difference alone: no hull's layout, mount count or
124
+ size differs from coriolis's.
125
+
126
+ - **Anaconda** `…Slot10_Size4`, then **`Slot13_Size2`, `Slot14_Size1`** — no 11 or 12.
127
+ - **Type-9 Heavy** starts at **`Slot00_Size8`**, the only hull that does, then runs
128
+ `Slot01`…`Slot08` and jumps to **`Slot11_Size2`, `Slot12_Size1`**.
129
+ - **Type-10 Defender** (`Type9_Military`) `Slot01`…`Slot08`, then the same
130
+ **`Slot11`/`Slot12`** jump.
131
+ - **Federal Dropship** `…Slot06_Size3`, then **`Slot09_Size2`, `Slot10_Size1`**.
132
+ - **Vulture** `Slot01`, `Slot02`, `Slot03`, **`Slot05`**, `Slot06`, `Slot07`, `Slot08`.
133
+ - **Type-7 Transporter** uses the number **`09` twice** (`Slot09_Size2` and
134
+ `Slot09_Size1` — distinct keys), and five of its ten suffixes misreport the size.
135
+ - **Keelback** `Slot03_Size3` on a size-**4** mount; **Asp Scout** `Slot01_Size4` on a
136
+ size-**5** one.
137
+ - **Type-8 Transporter** _hardpoints_ `…SmallHardpoint2`, **`SmallHardpoint4`**,
138
+ `SmallHardpoint5`, `SmallHardpoint6` — no `SmallHardpoint3`.
139
+ - **Caspian Explorer** _hardpoints_ `LargeHardpoint1`, **`MediumHardpoint6`**,
140
+ **`MediumHardpoint5`**, `MediumHardpoint1`…`4` — out of order, not merely gapped, so
141
+ the same key names a _different physical mount_ than position would suggest. Its
142
+ optionals are **not** overridden: EDSY gives none, and the Caspian capture below
143
+ confirms the plain numbering is right for them.
144
+ - **Lynx Highliner** `Slot01_Size6`, **`Passenger01`–`03`**, `Slot02_Size5`, …
145
+ - **Panther Clipper Mk II** and **Type-11 Prospector** are carried too, though the
146
+ regular numbering derives their names. They are kept so the stored table matches EDSY's
147
+ 13 entries one for one.
148
+
149
+ **The `_SizeN` suffix is Frontier's, and on three hulls it is wrong.** The Keelback, Asp
150
+ Scout and Type-7 name mounts with a class the hull does not have there. That is the
151
+ game's own text, not a transcription slip: `edsy.js` compensates for exactly this when
152
+ importing, taking the greater of the name's size and the fitted module's class. This
153
+ catalogue stores the name verbatim and keeps the mount's real size in the `optional`
154
+ entry beside it.
155
+
156
+ **Two numbering rules for a restricted mount** are derived from EDSY's name lists:
157
+
158
+ - a restricted **hardpoint** shares the per-size-class numbering with the unrestricted
159
+ ones and only takes an infix, so the Type-11's four medium mounts run
160
+ `MediumMiningHardpoint1`, `MediumMiningHardpoint2`, `MediumHardpoint3`;
161
+ - a restricted **optional** takes a name and number of its own and does **not** consume
162
+ a `SlotNN` number, exactly as `Military01` and `PlanetaryApproachSuite` do — so the
163
+ Panther's column runs `Cargo01`, `Slot01_Size8`, `Cargo02`, `Slot02_Size7`, …
164
+
165
+ EDSY's journal import map lists `HUGEMININGHARDPOINT`, `LARGEMININGHARDPOINT`,
166
+ `MEDIUMMININGHARDPOINT`, `SMALLMININGHARDPOINT`, `CARGO`, `LIMPETCONTROLLER` and
167
+ `FIGHTERBAY` as slot-name prefixes it must recognise, which is the other half of the
168
+ evidence that these are the game's strings.
169
+
170
+ **Checked against real captures.** Five exports were compared key by key against the
171
+ hull's enumerated layout: `slef-the-deep-black.jsonc` (Caspian
172
+ Explorer), `slef-inara-type-11.jsonc`, `slef-inara-lynx-highliner.jsonc`,
173
+ `slef-inara-panther-mkii.jsonc` and `slef-inara-cutter-antixeno.jsonc`. The Caspian
174
+ capture is the load-bearing one: its internals read `Slot01_Size7`…`Slot10_Size3`,
175
+ `Slot13_Size1`, `Slot14_Size1`, all of which the plain numbering produces — evidence for
176
+ leaving that hull's optionals alone rather than assuming EDSY omitted them. The Lynx
177
+ journal also supplies 29 outfitting keys, including its approach suite; its cosmetic
178
+ slots are outside the hull layout.
179
+
180
+ ### Per-hull source exceptions
181
+
182
+ - **Type-11 Prospector — eight hardpoints, not four.** The acquired record read
183
+ `hardpoints: [2, 1, 1, 1]`. Coriolis writes a _restricted_ hardpoint as an object
184
+ rather than a bare size and the Type-11 is the only hull in coriolis-data that has
185
+ any, so acquisition's "non-zero numbers are weapon mounts" rule silently dropped its
186
+ 3/2/2/1 mining mounts — leaving the game's dedicated mining hull with nowhere to fit a
187
+ mining tool, and no large mount at all for `Hpt_MiningToolV2_Fixed_Large`, which is
188
+ itself `restrictedToShips: ["LakonMiner"]` and so unfittable on the only hull that may
189
+ carry it. Stored as `[3, 2, 2, 2, 1, 1, 1, 1]`, which three sources agree on:
190
+ coriolis-data, EDSY `eddb.js` (`ship[…].slots.hardpoint = [3,2,2,2,1,1,1,1]`) and
191
+ Inara's ship page 68, read 2026-08-02 UTC, listing
192
+ 1 Large Mining, 1 Medium, 2 Medium Mining, 3 Small and 1 Small Mining. The four
193
+ unrestricted mounts are exactly the `[2, 1, 1, 1]` the record already had.
194
+ - **Lynx Highliner (`MediumTransport01`) — from EDSY, Frontier's Lynx update notes and
195
+ a Frontier journal capture:**
196
+ the Lynx has no coriolis hull entry, so its stats and slot layout are sourced instead
197
+ from EDSY's ship data and Frontier's Lynx update notes (hull mass 260 t, 285/350 m/s,
198
+ 200/350 base shield/armour, hardness 55, 2 crew, rotation 26/60/19 deg/s, min thrust
199
+ 73.75%; core PP5/thr6/FSD5/LS6/dist5/sen3/tank5; hardpoints 1 large + 4 medium;
200
+ 4 utilities; unrestricted/passenger optionals 6/6/6/5/5/4/4/3/2/1; its five armour
201
+ options at 0/26/53/53/53 t, carried on the `MediumTransport01_Armour_*` module
202
+ records). Values
203
+ the static catalogue does not expose are omitted rather than invented: `masslock`,
204
+ `heatCapacity`, `pipSpeed`, acceleration, and the min-pitch / boost-energy figures.
205
+ Its two size-6 and one size-5 passenger mounts carry `"restriction": "passenger"` and
206
+ the names `Passenger01`–`Passenger03`, sourced above. A final size-1
207
+ `planetaryApproachSuite` mount named `PlanetaryApproachSuite` comes directly from
208
+ `fixtures/ships/journal-lynx-highliner.jsonc`, which fits
209
+ `int_planetapproachsuite_advanced` there; that capture carries its own provenance in
210
+ its file header.
211
+
212
+ ## Modules (outfitting)
213
+
214
+ Each module is **one record** carrying its identity and its stats — identity from
215
+ FDevIDs, stats from coriolis-data and EDSY, joined on `symbol`.
216
+
217
+ - **Files:** `modules-core.jsonc`, `modules-internal.jsonc`,
218
+ `modules-hardpoint.jsonc`, `modules-utility.jsonc`, split along FDevIDs' four
219
+ outfitting categories.
220
+ - **Identity source:** FDevIDs `outfitting.csv`, columns
221
+ `id,symbol,category,name,mount,guidance,ship,class,rating,entitlement`, supplemented
222
+ for the six bundle-granted Vessel Hangars by the pinned CAPI response below.
223
+ - **Identity derivation:** the acquired FDevIDs module records are kept in CSV order
224
+ within each category file. The catalogue contains 484 internal records and **1199**
225
+ records across all four categories. The CSV's numeric `id`
226
+ column is dropped — modules are keyed by `symbol` — and rows marked `removed` are
227
+ excluded because they are not current outfitting modules. `class` is FDevIDs' `class` — the
228
+ module size (0–8) — and `rating` its grade letter (A–I); together they are the "5A"
229
+ the outfitting screen shows. `mount` (Fixed / Gimballed / Turreted) and `guidance`
230
+ (Dumbfire / Seeker / Swarm) are stored only on the hardpoints that carry them; `ship`
231
+ names the hull an armour variant belongs to (armour is the one ship-specific module,
232
+ so only the 241 armour records carry it); `entitlement` is kept only where it is a
233
+ real DLC/grant token. `name` is FDevIDs' descriptive English label, including expanded
234
+ forms such as Frame Shift Drive and Auto Field-Maintenance Unit.
235
+ - **The CSV's `category` column is not stored — the file states it.** It would be the
236
+ same string on every record. The CSV's category determines which file receives each
237
+ record.
238
+ - **`slot` — which fixed mount a module fills.** A category is not a mount: `core` is
239
+ eight of them. Every record in `modules-core.jsonc` names its own mount — `armour`,
240
+ or one of the seven core functions the ship records' `core` block is keyed by
241
+ (`powerPlant`, `thrusters`, `frameShiftDrive`, `lifeSupport`, `powerDistributor`,
242
+ `sensors`, `fuelTank`) — as do the fifteen Guardian Hybrid power plants and
243
+ distributors in `modules-internal.jsonc`, which fill a core mount although FDevIDs
244
+ files them as internal modules. No other record carries one: a weapon, a utility
245
+ fitting or an ordinary optional internal fits any mount of its kind that is large
246
+ enough, so there is no single mount to name.
247
+ - **Derivation:** the value is the mount the module is sold for in the outfitting
248
+ screen, assigned by symbol family — the 241 `*_Armour_*` records are `armour`, the
249
+ `Int_PowerPlant_*`/`Int_GuardianPowerplant_*` are `powerPlant`, and so on through
250
+ `Int_Engine_*` and `Int_MkIIAgileBoost_Engine_*` (`thrusters`), `Int_Hyperdrive_*`
251
+ (`frameShiftDrive`), `Int_LifeSupport_*`, `Int_PowerDistributor_*`/
252
+ `Int_GuardianPowerDistributor_*`, `Int_Sensors_*` and `Int_FuelTank_*`. Holding the
253
+ classification also covers the odd ones out: the Guardian hybrids and the Python Mk
254
+ II's `Int_MkIIAgileBoost_Engine_*` thrusters.
255
+ - **A fuel tank is the one module built for two kinds of mount:** it is `fuelTank`
256
+ and also fits any optional slot large enough, exactly as the game sells it.
257
+ - **`kind` is the engineering family.** The 1028 records mapped by
258
+ `engineering-options.jsonc` repeat that map's group key in the compact on-disk `kind`
259
+ field. The remaining 171 records carry no `kind` because the pinned sources publish
260
+ no engineering family for them. The group source, derivation, split
261
+ Guardian families and coverage are documented under Engineering options below; this
262
+ field is a projection of that map, not a separate classification source.
263
+ - **Stats source:** coriolis-data `modules/**` for the mechanical, defence, power and
264
+ weapon stats; EDSY `eddb.js` for mass, integrity, power draw, boot time and the
265
+ engineering base stats coriolis does not carry; and in-game verification for the
266
+ comprehensive audit and every game-settled correction below.
267
+ - **Stats derivation:** acquisition normalization looks up each module's coriolis
268
+ record by `symbol` (case-insensitively) and copies a fixed whitelist of fields under
269
+ clearer names — e.g. coriolis `optmass`→`optMass`, `fuelmul`→`fuelMul`,
270
+ `pgen`→`powerCapacity`, `wepcap`→`weaponsCapacity`. The repository's
271
+ `scripts/data/ships/merge-normalized-catalogues.mjs` performs the final checked
272
+ symbol join. The stat fields are sparse (only the ones a module's group uses) and
273
+ appended after the identity fields on the same record. Masses are tonnes, power
274
+ megawatts, jump ranges light-years, weapon ranges metres.
275
+ - **Defence, power and weapon stats:** coriolis-data supplies the resistances
276
+ (`kinres`/`thermres`/`explres`/`causres` →
277
+ `kineticResistance`/`thermalResistance`/`explosiveResistance`/`causticResistance`),
278
+ `hullreinforcement`→`hullReinforcement`, `shieldaddition`→`shieldAddition`,
279
+ `protection`→`moduleProtection`, `passive`→`alwaysPowered`, and the weapon block
280
+ (`damage`, `damagedist`→`damageDistribution` with the single-letter keys spelled out,
281
+ `roundspershot`→`roundsPerShot`, `fireint`→`burstInterval`, `burst`→`burstRounds`,
282
+ `burstrof`→`burstRateOfFire`, `charge`→`chargeTime`, `clip`→`clipSize`,
283
+ `ammo`→`ammoMaximum`, `reload`→`reloadTime`, `distdraw`→`distributorDraw`,
284
+ `thermload`→`thermalLoad`, `piercing`→`armourPiercing`, weapon/non-scanner utility
285
+ `range`→`maximumRange`, scanner `range`→`scannerRange`, `falloff`→`falloffRange`,
286
+ `shotspeed`→`shotSpeed`, `jitter`).
287
+ EDSY's `agzresist` enum supplies `guardianZoneResistance: true` on
288
+ `Hpt_ATVentDisruptorPylon_Fixed_Medium` and
289
+ `Hpt_ATVentDisruptorPylon_Fixed_Large`, the two Guardian Nanite Torpedo Pylons and the
290
+ only stock records whose value is `Active` in the pinned snapshot; the empty value on
291
+ every other record remains an omitted sparse field.
292
+ - **`rateOfFire` is derived, not copied.** Upstream stores the fire interval; the
293
+ journal (and this catalogue) report the combined shots per second, so it is
294
+ computed as `burst / ((burst − 1) / burstRateOfFire + fireInterval)`. Coriolis
295
+ (`Module.getRoF`) and EDSY (`rof = fpc / spc`) also fold `chargeTime` into this
296
+ figure, but Frontier does not: `journal-federation-corvette-mixed.jsonc` states
297
+ `RateOfFire` base values of 1.587302 for the small rail gun and 1.204819 for the
298
+ medium, exactly `1 / burstInterval` in both cases. Charge time is therefore kept as
299
+ the delay before impact but excluded from the reported firing cadence.
300
+ Continuous-fire weapons (beam and mining lasers) have no fire interval upstream and
301
+ so carry no `rateOfFire`; their `damage`, `distributorDraw` and `thermalLoad` are
302
+ already per second.
303
+ - **`maximumRange`/`falloffRange` describe weapons and non-scanner utility
304
+ effects.** A utility scanner's distance lives only in `scannerRange`; it is not
305
+ also exposed as a weapon range. Upstream's `range` is metres for anything
306
+ hardpoint-mounted but kilometres for sensors and its own units for limpet
307
+ controllers, so a value is carried only under the field whose meaning and unit are
308
+ unambiguous.
309
+ - **Two upstream zeroes are dropped rather than copied:** `roundspershot: 0` on two
310
+ Shock Cannon variants (Coriolis itself reads the field as `roundspershot || 1`; a
311
+ zero would zero their DPS) and `burstrof: 0` on the Mining Volley Repeater, whose
312
+ burst is a single shot.
313
+ - **`shotSpeed` and `reloadTime` are absent on the weapons that have neither, and
314
+ that absence is an answer.** The 49 weapons with no `shotSpeed` are the lasers, rail
315
+ guns, Gauss cannons and mine launchers — nothing there travels, so there is no
316
+ projectile speed to move. The 41 with no `reloadTime` are a _different and smaller_
317
+ family, the pulse, burst, beam and mining lasers alone: they have no clip and never
318
+ reload, while rail guns, Gauss cannons and mine launchers all reload and all carry
319
+ the stat. Neither registry publishes a figure for either set, and EDSY's per-family
320
+ `modifiable` lists say outright that the game does not move those stats on those
321
+ weapons. The two medium Seismic Charge Launchers, fixed and turreted, _do_ reload,
322
+ and take EDSY's `rldtime` of 1 s.
323
+ - **Module-breach stats** (`breachdmg`, `breachmin`, `breachmax`) are omitted from the
324
+ weapon block.
325
+ - **Massless modules state `"mass": 0` rather than omitting the field.** The registries
326
+ carry **no `mass` key at all** for fuel scoops, refineries, AFM units and docking
327
+ computers, and Coriolis's own code reads a missing mass as zero (`Module.getMass()` →
328
+ `this.mass || 0`). This catalogue reads an absent field as _unknown_ instead, so a
329
+ single such module would make a whole hull's mass — and with it its jump range —
330
+ impossible to compute. The 104 affected records (`Int_FuelScoop_*` ×40,
331
+ `Int_Repairer_*` ×40, `Int_Refinery_*` ×20, `Int_DockingComputer_{Standard,Advanced}`,
332
+ `ModularCargoBayDoor`, `Int_DroneControl_ResourceSiphon`) say so outright, matching
333
+ upstream's own `"mass": 0` on `Int_DetailedSurfaceScanner_Tiny`. **Verified, not
334
+ assumed:** summing the Deep Black's module masses with these families excluded gives
335
+ exactly the 1237.3 t its journal reports. The Resource Siphon was also observed in-game
336
+ at zero mass.
337
+
338
+ ### Engineering base stats — the values a recipe scales
339
+
340
+ Thirteen stored fields supply the base values referenced by engineering recipes:
341
+ `engineHeatRate`, `fsdHeatRate`, `refuelRate`, `shieldBankReinforcement`,
342
+ `shieldBankHeat`, `shieldBankSpinUp`, `shieldBankDuration`, `scannerRange`, `scanAngle`,
343
+ `scanTime`, `probeRadius`, `interdictorFacingLimit` and `interdictorRange`.
344
+
345
+ - **EDSY is primary here**, being the only one of the two registries that carries the
346
+ heat rates and the scanner stats at all. Cross-checked against coriolis-data
347
+ (`modules/**`, `modifications/modifierActions.json`, `modifications/blueprints.json`).
348
+ - **Which upstream field is which.** coriolis's `modifierActions.json` maps each journal
349
+ Modifier Label to the field it moves, and is what settles the joins:
350
+ `EngineHeatRate`/`FSDHeatRate`/`ShieldBankHeat` → `thermload`, `EnergyPerRegen` →
351
+ `distdraw`, `ShieldBankReinforcement` → `shieldreinforcement`, `ShieldBankSpinUp` →
352
+ `spinup`, `ShieldBankDuration` → `duration`, `ScannerRange` → `range`,
353
+ `SensorTargetScanAngle`/`MaxAngle` → `angle`, `ScannerTimeToScan` → `scantime`,
354
+ `FSDInterdictorFacingLimit` → `facinglimit`, `FSDInterdictorRange` → `ranget`. EDSY's
355
+ own attribute table names the same stats `engheat`, `fsdheat`, `scbheat`, `genpwr`,
356
+ `shieldrnfps`, `spinup`, `scbdur`, `scanrng`/`typemis`, `maxangle`/`scanangle`,
357
+ `scantime`, `facinglim`, `timerng`, `scooprate` and `proberad`.
358
+ - **The two registries agree everywhere both carry a value.** Shield cell banks, the
359
+ interdictors, the utility scanners, the sensor suites and the shield generators were
360
+ compared record by record; the one difference is a rounding, coriolis's `duration: 17`
361
+ against EDSY's `scbdur: 17.1` on the 8A cell bank, and EDSY's figure is kept as the
362
+ more precise. coriolis carries **no** `thermload` on thrusters or drives despite
363
+ naming the field in `modifierActions.json`, which is why EDSY is primary.
364
+ - **Units, where the two disagree about them.** `scannerRange` is stored in **metres**
365
+ throughout, which is what a journal reports and what EDSY stores; coriolis holds a
366
+ sensor suite's as kilometres (`5.76` for the 8D suite, `5760` here) and a utility
367
+ scanner's as metres. `probeRadius` is stored as a **percentage** (`20`), not a
368
+ fraction: that is EDSY's form, coriolis's `proberadius: 0.2` the other, and
369
+ `fixtures/ships/journal-krait-phantom.jsonc` settles it — the game reports the Detailed
370
+ Surface Scanner's `DSS_PatchRadius` as `20` → `28` for a grade-4 Expanded Probe
371
+ Scanning Radius roll. `interdictorRange` is **seconds to intercept**, the unit the
372
+ game measures a supercruise separation in, not a distance. `refuelRate` is tonnes per
373
+ second (EDSY `scooprate`); coriolis's `rate` is the same figure in kilograms.
374
+ - **A shield cell bank duplicates its heat under two stat names deliberately.** Its
375
+ `shieldBankHeat` is the same figure as its `thermalLoad` — one upstream field read
376
+ under two names. Scanner distance has one catalogue home instead: every utility
377
+ scanner and sensor suite carries
378
+ `scannerRange`, while `maximumRange` is reserved for weapons and non-scanner utility
379
+ effects.
380
+ - **`EnergyPerRegen` needs no stored value.** All 57 shield generators carry
381
+ `distributorDraw`, and EDSY (`genpwr`) and coriolis (`distdraw`) both confirm it is the
382
+ same stat under the journal's other name.
383
+ - **Nine figures no third-party registry lists, derived from the family rule.** Eight
384
+ records: the three `*_free` starter fittings (thrusters, drive, sensors — the sensors
385
+ contribute both a `scannerRange` and a `scanAngle`) and the five plain size-8 drives.
386
+ Each `*_free` record is byte-identical to its priced twin apart from the missing
387
+ `cost`, so it takes that twin's value. A drive's heat rate is a function of its **size
388
+ alone** across all 66 records EDSY does carry — 10, 14, 18, 27, 37, 43 for sizes 2 to
389
+ 7, identical between the plain and SCO lines at every size — and the size-8 SCO drives
390
+ are 50, so the size-8 plain drives take 50. Stated as derivation, not as a reading.
391
+ The Mk II supercharge-optimised size-8 SCO drive is **not** among them: EDSY publishes
392
+ its `fsdheat: 50` outright, spelling the fdname
393
+ `Int_Hyperdrive_Overcharge_Size8_Class5_Overchargebooster_MkII` where the outfitting
394
+ registry this catalogue is keyed on capitalises the `B`. The case-insensitive source
395
+ join makes it a reading.
396
+ - **A weapon with no maximum range carries no Long Range falloff leg.** That leg is
397
+ stored upstream as an overwrite in `[0, 1]` — a flag meaning "damage falls off from
398
+ maximum range." On the 33
399
+ weapons `Weapon_LongRange` reaches that have no range at all (missile and torpedo
400
+ racks, mine launchers, flak mortars, the AX dumbfires) there is nothing to resolve
401
+ against, and the recipe's `Range` leg is inert there for the same reason; the flag is
402
+ dropped rather than published as a one-metre falloff. Seven of the 33 do carry a real
403
+ `falloffRange` — the flak mortars, the AX dumbfire missiles and the Disruptor pulse
404
+ laser — and keep it unchanged: only the sentinel is ever dropped, and no record's
405
+ `falloffRange` is small enough to be mistaken for one.
406
+ - **A hull reinforcement package's hull boost is computed, not stored.** A
407
+ percentage-of-a-multiplier stat has no absent state, because no hull boost is a ×1
408
+ multiplier — 0% — and EDSY says so explicitly (`hullbst`, `default: 0`, `modmod: 100`).
409
+ A journal therefore reports `OriginalValue: 0`; no value is stored on any record.
410
+ - **`GuardianModuleResistance` grants a capability rather than scaling a stat.** EDSY
411
+ stores Anti-Guardian Zone Resistance as `agzresist`, an enumerated flag with values
412
+ `''` / `'Active'`, no unit and no magnitude. Inara displays the activation as +100%, but
413
+ treating that as an additive number would invent a base value the game does not have.
414
+ Apart from the two Guardian Nanite Torpedo Pylons that EDSY marks inherently `Active`,
415
+ stock catalogue records omit the sparse flag. No raw `Loadout` capture in this
416
+ repository states the modifier; its journal representation is therefore not treated as
417
+ Frontier provenance.
418
+
419
+ ### Deliberately absent fields
420
+
421
+ - **`integrity` is absent on 82 non-armour records** because no registry publishes one
422
+ for those families and the game's module panel shows none. Guardian hull reinforcement
423
+ packages are in that set and do draw power,
424
+ so "no integrity" is not a shorthand for "inert".
425
+ - **`cost` is absent** when no published price exists.
426
+
427
+ ### Reconciliation and in-game audit
428
+
429
+ The four module catalogues are reconciled against the registries and in-game
430
+ observations. EDSY fills values coriolis-data leaves blank; where either registry
431
+ disagrees with an in-game value, the in-game value governs.
432
+
433
+ EDSY supplies most module values that coriolis-data omits. In-game verification supplies
434
+ the remaining observable values, including the unsized Resource Siphon's zero mass.
435
+ Two starter capacities are derived rather than read:
436
+ `Int_FuelTank_Size1_Class3_free`'s `fuelCapacity` and
437
+ `Int_CargoRack_Size2_Class1_free`'s `cargoCapacity` follow from capacity being exactly
438
+ 2^size across all eight sizes of both families, with no exception.
439
+
440
+ **In-game coverage, stated separately from registry coverage.** In-game verification
441
+ covers **1193/1199** catalogue identities. Numeric verification covers **952/1199**
442
+ non-armour modules, and the other **241/1199** verified identities are the ship-specific
443
+ armour modules; their class, mass, hull boost and resistances retain their registry
444
+ provenance rather than being described as game-verified. The six bundle-granted Vessel
445
+ Hangars rely on the public registry and CAPI evidence below. Their stats match their
446
+ ordinary twins, but they have not been independently checked in the module panel.
447
+
448
+ Every numeric field available through in-game verification was compared. Exact
449
+ full-field coverage includes `powerDraw`
450
+ 831/837, `bootTime` 827/833, power-plant output and efficiency 43/43 each, every FSD
451
+ field 72/72, every thruster heat-rate record 40/40, all six distributor fields 49/49,
452
+ sensor range and angle 41/41, shield mass/strength curves 57/57, shield regeneration
453
+ 57/57, shield-cell timing/reinforcement/heat 40/40, fuel-scoop rate 40/40,
454
+ interdictor range/facing 20/20, cargo capacity 16/16, fuel capacity 9/9, hull
455
+ reinforcement 30/30, module protection 20/20, shield addition 10/10, Guardian jump
456
+ boost 5/5, weapon armour piercing 157/157, burst rounds 18/18, burst rate 16/16 and
457
+ rounds per shot 19/19. `powerDraw` and `bootTime` have no discrepancies at all.
458
+
459
+ In-game verification did not yield the 1173 store prices, hardpoint reserve ammo (120),
460
+ projectile speed (111), rail-gun charge time (3), or the 23 hardpoint scanners'
461
+ range/angle/time fields. Twenty-one hardpoint maximum-range values, ECM heat and reload,
462
+ the 241 armour modules, blueprint grade rolls and crafting costs remain unverified too.
463
+ It also did not unambiguously settle the shield-generator resistances, shield-booster
464
+ properties or probe radius. Those values are not changed on guesswork. For the 34
465
+ anti-xeno, Guardian and special weapons whose damage observed in-game does not reduce honestly
466
+ to one conventional scalar, `damageComponents` preserves the exact amounts. The two
467
+ channel types not established by in-game verification remain `unclassified`. Ten
468
+ projectile-limited hardpoints carry their boundary parameters observed in-game in
469
+ `projectileRange`; those parameters are not presented as effective ranges.
470
+
471
+ **A journal capture is a third source, and it reaches fields in-game verification does
472
+ not.** Every engineered module in a `Loadout` states its own _unmodified_ value beside
473
+ the modified one, so a capture reads base stats straight out of Frontier's own
474
+ arithmetic — including a hardpoint's reserve ammo and projectile speed, which the
475
+ in-game audit above lists as unreached, the shield-generator and shield-booster
476
+ resistances, which it lists as unsettled, and the ship-specific armour modules, which it
477
+ excludes from numeric verification altogether. Of the nineteen journal captures and the
478
+ EDSY export stored here, **eighteen state base values**; between them they state **1,070**
479
+ that name a field this catalogue holds, and every one agrees — 936 to the stored decimal
480
+ and 134 to within the game's own float noise.
481
+
482
+ Counted as distinct (module, label) pairs rather than per capture, that reaches 21
483
+ modules on their resistances (seven shield generators, two shield boosters, four hull
484
+ reinforcement packages and eight armour modules), those eight armour modules' hull
485
+ boosts, nine reserve-ammo and seven clip-size readings, and two projectile speeds.
486
+
487
+ **`Hpt_HeatSinkLauncher_Turret_Tiny` holds a reserve of 2**, which is a capture's figure
488
+ rather than a registry's. The Lynx Highliner states it under a grade-1 Heat Sink Capacity
489
+ that takes it to 3 — what 2 × 1.49 rounds to, where a base of 3 would have loaded 4 — and
490
+ the same block's `Mass` ×2 and `ReloadTime` ×1.5 legs read as the recipe defines them, so
491
+ the modifier is being read correctly. EDSY agrees at 2; coriolis-data's 3 is the figure the
492
+ corrections table below rejects. A hardpoint's reserve ammo is one of the fields the audit
493
+ above lists as unreached, which is why a capture is the source here.
494
+
495
+ **Three journal spellings reach a field only because a capture spells them that way.**
496
+ `Range` is a scanner's `scannerRange` — a weapon's `maximumRange` under the same label,
497
+ resolved per record; `DamageFalloffRange` is the
498
+ `falloffRange` a blueprint recipe calls `FalloffRange`, the same pairing as
499
+ `ProbeRadius` / `DSS_PatchRadius`; and `FuelScoopRate` is the `refuelRate` the
500
+ `FuelScoop_Efficiency` recipe calls `RefuelRate`. The nineteen readings behind the three
501
+ agree. The Caspian Explorer's grade-5 scoop roll reads 1.245 → 1.8675, the recipe's ×1.5,
502
+ and its `PowerDraw` leg reads ×1.15 in the same block.
503
+
504
+ A fourth label, `Jitter`, already resolved to `jitter`. A capture states it as
505
+ `OriginalValue: 0` on a missile rack whose record holds no such field — a weapon that
506
+ carries no jitter fires true. That zero is a value rather than an absence, so it is a
507
+ `defaultBase` like `roundsPerShot`'s 1. It applies to the 66 weapons offered Rapid Fire,
508
+ its multi-cannon spelling, or Inertial Impact (`special_distortion_field`) that hold no
509
+ jitter of their own.
510
+
511
+ **Eighteen weapons have a `DamagePerSecond` a capture states outright.** These are the only
512
+ external readings of an unmodified weapon's folded figure. On a beam laser the fold is
513
+ trivial because `damage` is already per second; the huge and medium gimballed beams have
514
+ no separate journal `Damage` reading.
515
+
516
+ **Every module in every catalogue carries at least one stat** (1199/1199), and no
517
+ record holds only a lone `mass`. 244 of the 833 `bootTime` values are `0` (every hardpoint
518
+ among them); they are stored rather than omitted, because an absent field means
519
+ absent.
520
+
521
+ **`Int_DroneControl_ResourceSiphon` has a mass of 0 t.** The value is read directly from
522
+ in-game: 0 t mass, alongside integrity 20, power draw 0.4 MW and boot time 0 s. It is not
523
+ inferred from EDSY's omitted field or from family uniformity; every sized limpet
524
+ controller in the family retains its real, non-zero mass.
525
+
526
+ **The three `*_free` starter fittings that would otherwise be hollow.**
527
+ `Int_ShieldGenerator_Size2_Class1_free` takes `shieldRegenRate` 1,
528
+ `shieldBrokenRegenRate` 1.6, the resistances 0.4 / −0.2 / 0.5 and `distributorDraw` 0.6
529
+ — **all six straight from EDSY**, which carries that record in full (as `genrate`,
530
+ `bgenrate`, `kinres`/`thmres`/`expres` as whole percentages, and `genpwr` for the
531
+ distributor draw). Rating-level uniformity gives the identical numbers — all eight
532
+ E-rated generators share those resistances — but it is not what these values rest on.
533
+ `Int_FuelTank_Size1_Class3_free` takes `fuelCapacity: 2` and
534
+ `Int_CargoRack_Size2_Class1_free` `cargoCapacity: 4`, and those two genuinely are
535
+ derived from the 2^size rule above. Without all three a stock starter fit reports 0 t of
536
+ fuel, 0 t of cargo and 0/0/0 shield resistances.
537
+
538
+ **Registry-derived corrections.** These are retained where in-game verification agrees
539
+ or where no corresponding in-game value was available:
540
+
541
+ | Records | Field | coriolis | Stored | Why coriolis's value is wrong |
542
+ | ---------------------------------------------------------------- | ----------------------------------- | -------------- | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
543
+ | `Int_GuardianPowerDistributor_Size{1,4,5,6,7,8}` | `integrity` | 56 | 35/70/99/99/115/132 | 56 is size 3's value, repeated across six sizes |
544
+ | `Int_GuardianPowerDistributor_Size3` | `weaponsCapacity`/`weaponsRecharge` | 13 / 3.1 | 17 / 3.9 | copied from an adjacent size |
545
+ | `Int_GuardianPowerDistributor_Size4` | `systemsCapacity`/`systemsRecharge` | 14 / 1.7 | 17 / 2.5 | copied from an adjacent size |
546
+ | `Int_Sensors_Size1_Class{1..5}` | `integrity` | 46/41/51/61/56 | 36/32/40/48/44 | coriolis's size-1 row is a verbatim copy of its size-2 row; size 1 is the only mismatching size in the family |
547
+ | `Int_PowerDistributor_Size1_Class{1..5}` | `integrity` | 46/41/51/61/56 | 36/32/40/48/44 | same duplicated-row defect |
548
+ | `Int_Hyperdrive_Overcharge_Size7_Class2` | `integrity` | 2700 | 150 | `optMass` copied into `integrity`; every sibling drive is 131–164 |
549
+ | `Hpt_Slugshot_{Fixed,Gimbal,Turret}_Medium` | `integrity` | 80 | 51 | 80 is the huge-mount value |
550
+ | `Hpt_Slugshot_{Fixed,Gimbal,Turret}_Large` | `integrity` | 80 | 64 | as above; the catalogue already had 64 on `Hpt_Slugshot_Fixed_Large_Range` |
551
+ | `Hpt_PulseLaserBurst_Gimbal_Huge` | `integrity` | 80 | 64 | a real outlier, not the Fragment Cannon rule misapplied — see "look wrong and are not" below |
552
+ | `Hpt_HeatSinkLauncher_Turret_Tiny` | `integrity` | 20 | 45 | 20 is the chaff launcher's; the Caustic Sink Launcher, its analogue, is 45 in both sources — the same duplicate-record defect as its `cost` and `mass` |
553
+ | `Hpt_MRAScanner_Size0_Class1` | `integrity` | 24 | 32 | every other size-0 scanner family runs 32/24/40/56/48; 24 is a duplicate of the Class2 row |
554
+ | `Int_DroneControl_{FuelTransfer,Prospector,Repair}_Size5_Class4` | `powerDraw` | 0.97 | 0.72 | 0.97 is the size-7 B-rated value; 0.72 holds the Class4/Class1 ratio the family keeps elsewhere (1.78 at sizes 1 and 3, 1.76 at size 7, 1.80 here) |
555
+ | `Hpt_Mining_SubSurfDispMisle_Turret_Small` | `powerDraw` | 0.42 | 0.53 | |
556
+ | `Int_ShieldGenerator_Size1_Class5_Strong` | `mass` | 2.5 | 2.6 | Prismatic is exactly 2× the base generator at every other size, so size 1 is 2×1.3, not half of size 2's 5.0 |
557
+ | `Int_ShieldGenerator_Size2_Class5_Strong` | `minMass` | 23 | 28 | |
558
+ | `Int_MetaAlloyHullReinforcement_Size1_Class2` | `mass` | 2 | 1 | |
559
+ | `Int_Engine_Size3_Class5` | `integrity` | 72 | 70 | |
560
+ | `Int_Powerplant_Size5_Class4` | `integrity` | 114 | 115 | |
561
+ | `Int_FSDInterdictor_Size2_Class2` | `integrity` | 51 | 31 | |
562
+ | `Hpt_Cannon_Gimbal_Large` | `damage` / `thermalLoad` | 37.39 / 2.9 | 37.421001 / 2.93 | observed in-game; the journal agrees |
563
+ | `Hpt_BeamLaser_Gimbal_Huge` | `thermalLoad` | 10.6 | 10.62 | observed in-game; the journal agrees |
564
+ | `Int_ShieldGenerator_Size7_Class5_Strong` | `shieldBrokenRegenRate` | 4.2 | 4.25 | observed in-game; the journal agrees |
565
+ | `Hpt_HeatSinkLauncher_Turret_Tiny` | `ammoMaximum` | 3 | 2 | a journal states the base as 2, and EDSY agrees; in-game verification does not reach hardpoint reserve ammo |
566
+ | `Hpt_Guardian_ShardCannon_Fixed_Medium` | `shotSpeed` | 1133 | 1133.333374 | Frontier's journal states the base beside the tech-broker Modified variant's engineered value |
567
+
568
+ **In-game corrections.** Values are stored at the observed in-game precision. These groups
569
+ account for 300 fields on 135 modules in addition to the Resource Siphon:
570
+
571
+ | Records | Fields | Stored in-game values |
572
+ | ----------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------- | ------------------------------------------------------------------ |
573
+ | `Int_Engine_Size4_Class{2,4}`, `Int_Hyperdrive_Size4_Class4` | thruster min/max mass; FSD optimal mass | 158/473, 193/578 and 438 t |
574
+ | `Int_Engine_Size{2,3}_Class5_Fast` | optimal/maximum multiplier | 1.1 / 1.2 on both |
575
+ | `Int_GuardianShieldReinforcement_Size{1..5}_Class{1,2}` | integrity | 36/42, 40/48, 45/55, 51/63, 58/72 |
576
+ | `Int_MetaAlloyHullReinforcement_Size{1..5}_Class{1,2}` | caustic resistance | 0.02 on all ten |
577
+ | shield generators | regeneration / broken regeneration | observed 1.06–5.76 values per symbol |
578
+ | `Int_ShieldCellBank_Size1_Class2`; `Int_FuelScoop_Size4_Class5` | reserve ammo; scoop rate | 1; 0.343 t/s |
579
+ | Beam Laser, Cannon, Fragment Cannon, Multi-Cannon, Plasma Accelerator, Rail Gun, Shock Cannon and Point Defence records | damage / thermal load | 34 scalar damage and 55 thermal-load corrections |
580
+ | Advanced Plasma Accelerator, Imperial Hammer, Shock Cannons and Mk II Plasma Shock Accelerator | burst interval / combined rate of fire | exact cycle values derived with the catalogue's documented formula |
581
+ | mining, utility and Guardian hardpoints | clip, distributor draw, reload, jitter, falloff and maximum range | observed values per symbol |
582
+ | anti-xeno, Guardian and special weapons | scalar, distribution and exact damage components | 34 component records |
583
+ | AX missiles, subsurface displacement missiles and seismic charge launchers | projectile boundary parameters; misleading ordinary ranges absent | ten records and 16 absences |
584
+
585
+ In-game verification gives the integer thruster/FSD masses, 1.1/1.2 enhanced-thruster
586
+ multipliers and the rising Guardian Shield Reinforcement integrity ladder. These values
587
+ take precedence over family-shaped inference and registry agreement.
588
+
589
+ **The two fixed Guardian Shard Cannons' damage is derived from a panel reading, not read
590
+ off one.** Individual outfitting panels observed **2026-08-10 UTC**, with grade-1
591
+ Anti-Guardian Zone Resistance active on both weapons, display **5.2 damage / 104.5
592
+ damage/s** on the fixed large and **3.7 damage / 74.5 damage/s** on the fixed medium; a
593
+ six-shard build's panel adds a 566.9 damage/s total. The panel exposes only rounded
594
+ values, so it does not uniquely reveal the underlying decimals. The stored **5.225** and
595
+ **3.7235** damage per projectile apply the uniform 10% correction all three readings
596
+ indicate to the older registry figures 4.75 and 3.385; at 12 projectiles and 1.666667
597
+ shots/s they reproduce both individual displays and the build total. The remaining fields
598
+ those panels state agree with the catalogue as stored (8/4 t mass, 51/42 integrity,
599
+ 1.68/1.21 MW power, 1.4/0.65 MW distributor draw, 2.2/1.2 thermal load, 60/45 armour
600
+ piercing, 1700 m maximum and falloff ranges, 5/180 ammunition, 1133/1133.333374 m/s
601
+ projectile speed). A panel reading has no upstream immutable revision.
602
+
603
+ **The two fixed Guardian Gauss Cannons' damage comes directly from stock module-panel
604
+ readings.** Individual outfitting panels observed **2026-08-12 UTC** display **22.0**
605
+ damage for the small 1D cannon and **38.5** for the medium 2B cannon. Those readings
606
+ settle the registry disagreement in favour of coriolis-data's 22 / 38.5 rather than
607
+ EDSY's 40 / 70. The catalogue stores the displayed values without further derivation and
608
+ applies the same correction to their exact thermal and anti-xeno components. The two
609
+ records are pinned in `fixtures/ships/module-stats.jsonc`. A panel reading has no upstream
610
+ immutable revision.
611
+
612
+ **Values that look wrong and are not.** Three records break the pattern their family
613
+ follows and are confirmed outright by EDSY. Recorded so the "breaks its family's curve"
614
+ heuristic does not keep rediscovering them:
615
+
616
+ - **`Hpt_PulseLaserBurst_Gimbal_Huge` `integrity` really is 64**, and it really is the
617
+ only huge (class-4, 16 t) hardpoint not at 80 — its own fixed sibling is 80. EDSY gives
618
+ `integ:64` for it and 80 for the other eleven. Note that EDSY also gives it
619
+ `maxbrc: 80`, which is max **breach** damage and is easy to misread as the integrity.
620
+ - **`Int_GuardianPowerDistributor_Size{5,6}` `integrity` really are both 99.** Guardian
621
+ distributor integrity otherwise tracks 0.80× the A-rated standard ladder, which would
622
+ put size 5 near 85; EDSY states 99 for both sizes. The duplicate is in the game data.
623
+ - **`Int_DroneControl_Recon_Size5_Class1` `bootTime` really is 9.85** — the only
624
+ non-integer boot time in all 1199 records, where its three family siblings are exactly 10.
625
+ EDSY gives `boottime:9.85`.
626
+
627
+ ### Prices — `cost` on modules, `hullCost` / `retailCost` on hulls
628
+
629
+ `cost` is the module's standard list price in credits, before any station discount or
630
+ markup — the figure an outfitting screen quotes at 0% discount. On hulls, `hullCost` is
631
+ the bare hull and `retailCost` the hull with its default module loadout (`retailCost` is
632
+ never below `hullCost`). Sources are coriolis-data's `cost` per
633
+ module and `properties.hullCost` / `retailCost` per ship, with EDSY filling the records
634
+ coriolis does not price (the newer hulls' armour and Operations additions) and supplying
635
+ the Lynx Highliner, which has no coriolis entry.
636
+ Ship-specific **armour** is priced from each hull's `bulkheads` upstream, joined on hull
637
+ and bulkhead name because those records carry no symbol upstream.
638
+
639
+ - **All 48 hulls are priced. 1173 of 1199 modules are.** The 26 without a price are the
640
+ fifteen grant/starter `*_free` variants, the five size-8 frame shift drives, the three Mk II
641
+ Vessel Hangars, the two unsold Corrosion Resistant Cargo Racks (both Community Goal
642
+ rewards) and `Int_ShieldGenerator_Size1_Class4` — no registry publishes a figure for
643
+ them. **`cost` is omitted, never set to 0**: `0` is a real price (the starter
644
+ Lightweight Alloy bulkhead costs nothing), while omission means unknown.
645
+ - **Sixteen duplicated symbols take the first occurrence's price.** Where coriolis-data
646
+ holds a symbol twice, the "first occurrence wins" rule that governs `mass` governs
647
+ `cost` too; taking the _second_, unpriced record would leave them at `0`. The sixteen:
648
+ `Hpt_HeatSinkLauncher_Turret_Tiny` 3500 — confirmed independently against a real
649
+ journal, which prices the fitted module at 3071 = 3500 less the 12.25% outfitting
650
+ discount that export was taken at; `Int_Hyperdrive_Size5_Class5` 5 103 953;
651
+ `Int_CargoRack_Size5_Class1` 111 566 and `_Size6_Class1` 362 591;
652
+ `Int_DetailedSurfaceScanner_Tiny` 250 000; `Hpt_MultiCannon_Fixed_Medium` 38 000;
653
+ `Hpt_Railgun_Fixed_Medium` 412 800; `Hpt_BasicMissileRack_Fixed_Medium` 512 400;
654
+ `Hpt_MiningLaser_Fixed_Small` 6800; `Hpt_ATDumbfireMissile_Fixed_Large` 1 352 250;
655
+ and the six small/medium Guardian weapons (Gauss 167 250 / 543 801, Plasma
656
+ 176 500 / 567 761, Shard 151 650 / 507 761).
657
+ - **Only one record is priced `0`:** `ModularCargoBayDoor`, which is built into every
658
+ hull and cannot be bought. A zero price is otherwise indistinguishable from a dropped
659
+ one, so a new one has to be argued for.
660
+ - **`Int_CorrosionProofCargoRack_Size1_Class2` is priced at 12 560, from EDSY**, where it
661
+ is module `161`, annotated `// at Palin, Sedesi`. Coriolis reads `cost: 0` for it,
662
+ which is coriolis's own gap and not a shared one: on the two corrosion racks _both_
663
+ registries price they agree exactly (`_Size1_Class1` 6250, `_Size4_Class1` 94 330), and
664
+ the only corrosion racks FDevIDs `outfitting.csv` lists at all are those two plus
665
+ `_Size1_Class2` itself — so it is the last of the purchasable ones. It is certainly not
666
+ free: the Deep Black's journal buys the size-4 at 82 775 = 94 330 less that export's
667
+ 12.25% discount.
668
+ - **Read that 12 560 as a 10-granular figure, not a to-the-credit one.** EDSY publishes
669
+ module costs at **10-credit granularity**, which is measured rather than assumed. Two
670
+ observations, both scoped to `eddb.module` — EDSY's outfitting table, where module
671
+ `161` lives — so they can be re-run. Totals across the whole of `eddb.js` are
672
+ deliberately not quoted: they move with how the scan treats commented-out records,
673
+ the ship table's own armour rows and case-mismatched symbols, whereas within the
674
+ module table the result is flat.
675
+ - **Every cost in that table is a multiple of 10 but one:**
676
+ `Int_ShieldGenerator_Size1_Class5`, at 88 075. (Take in the ship table's own armour
677
+ rows as well and eight more appear — Python Mk II and Cobra Mk V — and the hull
678
+ prices in that table add three more again, for the Python Mk II, Cobra Mk V and
679
+ Panther Clipper Mk II. That spread is exactly the method-dependence being avoided
680
+ by scoping to the module table.)
681
+ - Where coriolis prices the same module and the two differ, the difference is
682
+ overwhelmingly EDSY carrying coriolis's exact figure rounded to the nearest 10
683
+ (`Int_CargoRack_Size5_Class1` 111 566 → 111 570, `_Size6_Class1` 362 591 →
684
+ 362 590). A minority are the registries disagreeing about the price itself rather
685
+ than about precision, sometimes widely
686
+ (`Hpt_MkIIPlasmaShockAutocannon_Fixed_Large`: EDSY 4 612 670, coriolis 3 051 200),
687
+ so read a lone EDSY figure as possibly stale as well as rounded.
688
+
689
+ **What that does and does not bound.** It bounds the _rounding_ to under 10 credits,
690
+ and not to ± 5: EDSY does not always round to nearest, since among the pairs differing
691
+ by under 10 credits a handful differ by 6 to 9, and EDSY is _above_ coriolis in every
692
+ one of them (`Int_LifeSupport_Size8_Class5`: coriolis 27 249 391 → EDSY 27 249 400).
693
+ It does **not** bound how far the figure sits from the game's own price. Three pairs
694
+ where both registries publish a multiple of 10 still differ by 10
695
+ (`Int_FighterBay_Size{6,7}_Class1`, `Int_PassengerCabin_Size6_Class1`), which no
696
+ rounding explains: whatever the real price is, at least one of the two registries is
697
+ wrong about it by five credits or more, and neither says which. So treat 12 560 as the
698
+ best published figure at 10-credit resolution, not as an accuracy guarantee; only an
699
+ in-game reading settles the last digits. Every EDSY-sourced price in this catalogue
700
+ carries the same granularity, so this record is no less exact than the rest of them.
701
+ - **The size-5 and size-6 Corrosion Resistant Cargo Racks have no list price to
702
+ publish**, and their absent `cost` means _no list price exists_, not _none has been
703
+ found_. They are **not sold at any station**: FDevIDs `outfitting.csv` lists neither,
704
+ and EDSY hides both with `cost: 0 // TODO: cost // CG reward`. They were Community Goal
705
+ rewards and were sold nowhere. Frontier's own announcement of the **Rhea Disaster** CG
706
+ states that "all participating commanders will now receive the Size 6 Corrosion
707
+ Resistant Cargo Rack whilst the top 50% will now receive 2"
708
+ (post id `1812792503776489745`; the CG itself ran on the Frontier forums, thread
709
+ `626528`). The Elite Dangerous Wiki's Corrosion Resistant Cargo Rack page records
710
+ that the class 5 and 6 modules "exist in limited numbers among CMDRs who received them
711
+ as a Community Goal reward, but they are otherwise neither purchasable nor
712
+ unlockable" — size 4 is the largest one obtainable, through a Human Technology Broker.
713
+ So EDSY's `TODO: cost` is upstream expecting a figure that outfitting never quoted.
714
+ Players do hold these racks, so a journal can name them and the catalogue must resolve
715
+ them; `cost` stays omitted, since a reward module still has an insurance value and
716
+ reporting it as free would understate a rebuy.
717
+ - **Both sources were read 2026-08-06 UTC; the wiki is unpinned.** An X status id
718
+ names one immutable post, so the announcement is pinned by its URL. The wiki page is
719
+ mutable and MediaWiki serves a stable `?oldid=` for it, but the host refuses
720
+ automated requests from this environment (HTTP 403), so neither the revision id nor a
721
+ stored copy could be captured and `../SNAPSHOTS.md`'s checksum fallback is out of
722
+ reach for the same reason. The quotation above is the preserved form; no revision is
723
+ invented.
724
+ - **What an unpinned source may carry: an interpretation, never a value or a record.**
725
+ Nothing in any payload here derives from either of these two; they settle only what an
726
+ already-absent `cost` means.
727
+ Using an unpinned page to add a price or a module would need the pin first.
728
+ - **A capture reporting a `Value` was checked and rejected.**
729
+ `fixtures/ships/slef-inara-cutter-antixeno.jsonc` fits five of these racks. Its two
730
+ size-6 records carry **no `Value` at all**; its size-5 carries `Value: 318174`. That
731
+ is not a list price, and the same export is what proves it: the two size-4 racks in it
732
+ read **82 774** and **91 970** against the one list price of 94 330 — about 12.25% and
733
+ 2.5% off. `Value` is net of the station discount, one reading with an unknown discount
734
+ does not yield a list price, and a reward module was not bought at a discount to begin
735
+ with. (318 174 is within a credit of 362 591 less 12.25%, and 362 591 is the
736
+ _standard_ E-rated size-6 rack's price; that is arithmetic reaching for a target with
737
+ a free variable, not a source.)
738
+ - Adding a value requires an in-game reading that does not go through a purchase: a
739
+ `StoredModules` entry's `BuyPrice`, a `ModuleSell` on one, or the insurance figure a
740
+ rebuy screen quotes. A journal `Loadout` `Value` is not sufficient, for the reason above.
741
+ - **Filled by hand, from a documented uniformity:** `Int_ShieldGenerator_Size1_Class4`
742
+ (added from EDSY, so it has no coriolis record) takes the resistances and distributor
743
+ draw every one of the 55 shield generators coriolis does carry shares — kinetic 0.4,
744
+ thermal −0.2, explosive 0.5, draw 0.6. The cargo hatch (`ModularCargoBayDoor`) takes
745
+ the 0.6 MW draw Coriolis hard-codes for it (`ModuleUtils.cargoHatch`), since it is
746
+ fitted to every hull and cannot be removed.
747
+ - **Not modelled:** passenger capacity and fighter-bay/rebuild counts. The
748
+ **Merc-Coin** price of the pre-engineered variants is carried, but on the variant
749
+ rather than the module — see `mercCoinCost` in the pre-engineered section.
750
+
751
+ ### Armour, and the fields kept deliberately
752
+
753
+ - **Armour (bulkhead) stats:** coriolis keeps a hull's five (Caspian Explorer: six)
754
+ armour options on the _hull_ record; this catalogue keeps them on the matching
755
+ `<Hull>_Armour_*` module records, joined by hull and by the symbol's grade suffix
756
+ (`_Grade1`, `_Grade1_Default`, `_Grade2`, `_Grade3`, `_Mirrored`, `_Reactive`). Each
757
+ carries its added `mass` (t), `hullBoost` (the fraction of the hull's base armour it
758
+ adds on top) and the four resistances. Armour is a module like any other, so its stats
759
+ live with every other module's rather than being duplicated on the hull. The Lynx
760
+ Highliner has no coriolis hull entry, so its options take the per-grade hull boost and
761
+ resistances that all 47 hulls coriolis does carry share, with the masses from EDSY.
762
+ - **Deliberate stat fields:**
763
+ - **`restrictedToShips`** carries the hull symbol(s) a non-armour module is limited
764
+ to (coriolis's `ship` field: the MkII Gravity Optimised thrusters → `Explorer_NX`,
765
+ the MkII Agile Boost thrusters → `SmallCombat01_NX` "Kestrel", the MkII Mining
766
+ controller and Mining Volley Repeater → `LakonMiner`), plus the two Mk II Cargo Racks
767
+ → `["PantherMkII"]` (EDSY marks them `reserved:{63:1}`, ship 63 being the Panther
768
+ Clipper Mk II, and coriolis-data describes them as a "Panther Clipper storage rack")
769
+ and the three Mk II Vessel Hangars → `["Explorer_NX", "PantherMkII", "LakonMiner"]`
770
+ (EDSY has no record for the Mk II bays at all, so their restriction rests on
771
+ Frontier's update notes and Inara). Armour records use the `ship` field instead.
772
+ - **`restrictedToSlot`** is the same idea one axis over: the slot restriction a module
773
+ requires, so it fits only mounts carrying it — the mirror of a mount's `restriction`,
774
+ and the half `restrictedToShips` cannot express. Five records have one: the two
775
+ planetary approach suites, the two Mk II Cargo Racks and the Mk II Mining
776
+ Multi-Limpet Controller. It composes with `restrictedToShips` rather than replacing
777
+ it — the racks name both the hull that can buy them and the mount they go in.
778
+ - **Sources.** EDSY refuses a reserved `icr` outside a slot named `CARGO*`, and
779
+ coriolis-data carries `"restriction": "Cargo"` on the module; the same shape holds
780
+ for the Mk II Mining Multi-Limpet Controller against `LIMPETCONTROLLER*`.
781
+ `fixtures/ships/slef-inara-panther-mkii.jsonc` shows the game agreeing: its two Mk II
782
+ racks sit in `cargo01` and `cargo02` while its _unrestricted_ `slot01_size8` and
783
+ `slot02_size7` carry ordinary racks — a build that could not exist if the
784
+ reservation were about size. `fixtures/ships/slef-inara-type-11.jsonc` does the same
785
+ for the controller, in `limpetcontroller01`.
786
+ - **The field is deliberately narrow.** It says a module fits _only_ mounts with that
787
+ restriction, so it is wrong on anything the game also sells for an ordinary
788
+ optional: a plain cargo rack fits a `cargo` mount _and_ every unrestricted one, and
789
+ does not carry it. The set of five is pinned, so widening it is a deliberate act.
790
+ - **Pre-engineered/duplicate drives share a `symbol`** in coriolis (e.g. the V1
791
+ FSDs); the first (primary) occurrence wins, and any baked engineering is expected
792
+ to arrive as SLEF `Engineering.Modifiers` instead.
793
+ - **Identity retained verbatim from the source:**
794
+ - The `?` notes on `Hpt_CausticSinkLauncher_Turret_Tiny` and
795
+ `Hpt_AntiUnknownShutdown_Tiny_V2` are not entitlement tokens and are omitted.
796
+ - One source row (`Int_MkIIAgileBoost_Engine_Size5_Class5`) has the literal string
797
+ `mount` in its `mount` column — a thruster has no hardpoint mount, so the field
798
+ is omitted, matching every other thruster.
799
+ - **`Int_LargeCargoRack_Size8_class1` really is spelled with a lower-case `class1`**
800
+ — the only record in all four catalogues that is. It is not a typo here: EDCD
801
+ FDevIDs `outfitting.csv` spells it exactly that way (row `129034964`), and identity
802
+ comes from FDevIDs. EDSY normalises it to `_Class1`, which is why a cross-check
803
+ against EDSY looks like it disagrees. The stored symbol retains FDevIDs' casing.
804
+
805
+ ### Records sourced outside the baseline registries
806
+
807
+ Records not in coriolis-data / FDevIDs at the acquired revisions:
808
+
809
+ - **Vessel Hangars** — the three Mk II records
810
+ (`Int_FighterBayMk2_Size{5,6,7}_Class1`) have the same operational stats as the Mk I
811
+ bays at half the mass (10/20/30 t, integrity 60/80/120, power
812
+ 0.25/0.35/0.35 MW). The three Mk I **Fighter Hangar** records are named **Mk I Vessel
813
+ Hangar** (same symbols and stats; the Operations update renamed them and let them
814
+ deploy the Nomad).
815
+ - **Six bundle-granted variants are separate identities.** The pinned CAPI response
816
+ lists `Int_FighterBay{,Mk2}_Size{5,6,7}_Class1_Free` as modules with `bundle: true`
817
+ and the grant tokens `ELITE_V_MKIFIGHTERBAY_FREE` / `ELITE_V_MKIIFIGHTERBAY_FREE`.
818
+ That is direct player-facing evidence that they are obtainable, so they pass the
819
+ inclusion rule below despite remaining absent from FDevIDs. The later EDSY snapshot
820
+ independently lists all six and supplies the same mass, integrity, power draw and
821
+ boot time as their ordinary twins. The Mk II grant variants retain the ordinary Mk
822
+ II restriction to `Explorer_NX`, `PantherMkII` and `LakonMiner`; the Mk I variants
823
+ remain unrestricted like their ordinary twins. `cost` is omitted: the CAPI response's
824
+ zero is the bundle charge, not a standard purchase price for a separately sold
825
+ module.
826
+ - **Mk II passenger cabins** (`Int_MkII_PassengerCabin_Size{2..6}_Class{1,2}`) — identity
827
+ records from FDevIDs, with mass added (2.5/5/10/20/40 t by size) and the two size-6
828
+ records' `class` corrected from 5 to 6.
829
+ - **Corrosion Resistant Cargo Racks** `Int_CorrosionProofCargoRack_Size{5,6}_Class1`
830
+ (capacity 32/64) and the built-in **Cargo Hatch** `ModularCargoBayDoor` (power 0.6 MW)
831
+ — live EDSY records (not commented out, unlike the 1B shield generator below) that the
832
+ FDevIDs join omits. Both racks carry EDSY's `hidden:1`, and they are also the two the
833
+ prices section leaves unpriced, but the flag is not the reason: `hidden:1` marks a
834
+ record EDSY keeps out of its pickers for assorted reasons, and of the nine such records
835
+ in its module table one does carry a price (`Int_DroneControl_ResourceSiphon`,
836
+ `cost: 18040` — which EDSY itself annotates `// bug?`, so it is a weak counter-example,
837
+ but enough to show the flag is not a statement about price).
838
+ - **`_Size2_Class1` is not carried: it never existed in game.** No registry lists it as
839
+ player-obtainable, which is the inclusion rule below failing rather than a price gap —
840
+ FDevIDs `outfitting.csv` has no row, coriolis-data has no record at all, and EDSY
841
+ carries it `cost: NaN` annotated "never released". A variant that never reached
842
+ players is not a player-facing outfitting record, so it goes the way of the other
843
+ non-purchasable internal variants that rule excludes.
844
+ - **1B Shield Generator** (`Int_ShieldGenerator_Size1_Class4`) — a gap in FDevIDs, not
845
+ in the game: every other shield-generator size carries all five ratings, and size 1
846
+ ran E/D/C/A with **B missing**. The module is real, so the record is carried with the
847
+ stats its sources do expose — `optMass` 25 t, `minMass` 13 t, `maxMass` 63 t,
848
+ multipliers 0.6 / 1.1 / 1.6, regen 1.0 / 1.6 MJ/s. **`mass`, `integrity` and
849
+ `powerDraw` are deliberately omitted**: EDSY carries this variant commented out with
850
+ those three fields blank (identity `fdid` 128064261 and the multipliers only), and no
851
+ other registry publishes them. Omitted rather than interpolated from the neighbouring
852
+ ratings — see the Lynx note under §Ships for the same rule.
853
+
854
+ ### What is not carried, and why
855
+
856
+ - **Deliberately not modelled here:** the **Merc-Coin pre-engineered weapon variants**
857
+ are not separate module records: their base module symbols already exist, and the
858
+ pre-engineering is expressed as the Operations blueprints below — the pairing between
859
+ the two is `pre-engineered.jsonc`. The **Nomad** (`Lander01`) is a ship-launched
860
+ vehicle, not a shipyard hull, and its `Vehicle_Lander01_*` weapons carry no
861
+ category/class/rating the module schema requires, so neither the vessel nor its modules
862
+ are added.
863
+ - **Inclusion rule:** a module symbol is carried only when FDevIDs, coriolis-data or EDSY
864
+ lists it as player-obtainable outfitting, or a direct player-facing capture establishes
865
+ the same thing.
866
+ - **Symbols outside outfitting are not stored** — hull geometry, ship-launched-fighter
867
+ weapons and internals, station fittings, and non-purchasable internal or test variants.
868
+ - **A named variant with no published stats is not stored either.** Where a registry
869
+ records only that a variant exists, its missing values are not invented. The one
870
+ exception is documented above
871
+ (`Int_ShieldGenerator_Size1_Class4`), where the multipliers _are_ published and only
872
+ the three unknown fields are omitted.
873
+ - The built-in **Cargo Hatch** is stored once as `ModularCargoBayDoor`; per-hull
874
+ duplicates of the same fitting are not carried separately.
875
+
876
+ ## Engineering (blueprints and experimental effects)
877
+
878
+ In-game verification found 129 blueprint identities and 89 experimental/special
879
+ identities. It did not yield blueprint grade rolls, ingredient quantities or crafting
880
+ costs, so those tables retain the separately pinned sources below. All 133 experimental
881
+ modifier legs available for numeric in-game verification agree. The in-game evidence did
882
+ not settle every modifier's association with the library's public stat label, so those
883
+ associations retain their separately sourced mapping. Experimental display strings were
884
+ also verified in-game.
885
+
886
+ **Rate-of-fire features carry the label of the stat they change.** Frontier's own
887
+ `Weapon_RapidFire` and `Weapon_HighCapacity` recipes modify the **fire interval** —
888
+ coriolis-data stores the feature as `rof` but flags it `higherbetter: false`, and its own
889
+ calculator inverts it (`Module.js`: `if (name == 'rof') modValue = 1/(1+modValue) - 1`),
890
+ while EDSY stores the same recipes outright as burst-interval modifiers
891
+ (`bstint:[-8,-17,-26,-35,-44]`). Those ten features are therefore stored here under
892
+ **`BurstInterval`**, the stat they actually move; a weapon's combined `rateOfFire`
893
+ follows from the interval and its burst pattern. The Inara-sourced Operations totals are
894
+ left as published: they are _displayed_ rate-of-fire changes, so they keep the
895
+ `RateOfFire` label and apply to the rate directly — which is the only reading that
896
+ reproduces the published figure on a charged weapon such as the rail gun.
897
+
898
+ **`special_hullreinforcement_*` stores its `DefenceModifierHealthAddition` leg as
899
+ `multiplicative`, not `additive`.** Both sources give it as a percentage — coriolis's
900
+ `modifierActions` treats `hullreinforcement` as a multiplicative percentage and EDSY
901
+ stores `ihrpx_ap: { hullrnf: -5 }` — so reading it additively would apply a flat 0.05
902
+ hull points. The label only bites at all because hull reinforcement packages carry a
903
+ `hullReinforcement` base for it to apply to.
904
+
905
+ **Four effects carry a benefit leg only one of the two sources spells out.** Each names
906
+ a modification whose drawback is easy to find and whose benefit is not, so an effect
907
+ holding the drawback alone looks complete while doing nothing a build would notice. Both
908
+ references agree on every value below:
909
+
910
+ | Effect | Drawback leg | Benefit leg |
911
+ | -------------------------------------------------------- | ------------------------------------- | ------------------------------------------- |
912
+ | `special_weapon_damage` (Oversized) | `PowerDraw +5%` | `Damage +3%` |
913
+ | `special_weapon_rateoffire` (Multi-servos) | `PowerDraw +5%` | `BurstInterval −2.9126%` |
914
+ | `special_powerdistributor_capacity` (Cluster Capacitors) | three capacity legs, one recharge leg | `WeaponsRecharge` and `SystemsRecharge` −2% |
915
+ | `special_powerdistributor_fast` (Super Conduits) | three capacity legs, one recharge leg | `WeaponsRecharge` and `SystemsRecharge` +4% |
916
+
917
+ Multi-servos is stored under `BurstInterval` for the reason given above — EDSY writes it
918
+ as `bstint: -2.9126…`, coriolis as `rof: -0.029126…` under its inverted convention, and
919
+ both come to the same +3% rate of fire.
920
+
921
+ **Excluded: two single-sourced canister magnitudes.** coriolis gives
922
+ `special_radiant_canister` an `ammo: -0.25` and `special_shiftlock_canister` a
923
+ `damage: -0.2`; EDSY records no magnitude for either, its `special:` text describing only
924
+ the gameplay flag ("Area heat increased and sensors disrupted", "Area FSDs reboot"). The
925
+ in-game descriptions coriolis carries do say a cost exists ("at the cost of ammo
926
+ capacity" / "at the cost of reduced damage"), so the _direction_ is not in doubt — but a
927
+ magnitude a single source asserts is worse than this file's standing convention for a
928
+ qualitative effect: an empty `modifiers` list and a `description`. Both keep that, and a
929
+ numeric modifier is not inferred.
930
+
931
+ **Excluded: `special_plasma_slug_pa`.** coriolis splits Plasma Slug into a legacy id
932
+ (`special_plasma_slug`, named "Plasma slug (Legacy)", damage −20%) and a current
933
+ plasma-accelerator id (`special_plasma_slug_pa`, damage −10%). EDSY carries no `_pa` id
934
+ at all, and where it has to disambiguate — `edsy.js` `Build.fromCAPI`, importing a
935
+ Frontier API loadout — it does so by module type, mapping a rail gun's
936
+ `special_plasma_slug` to `special_plasma_slug_cooled`. `Build.fromJournal` looks the id
937
+ up straight through with no disambiguation at all. Both paths are evidence that
938
+ `special_plasma_slug` is the id the game writes. This repo follows EDSY: one
939
+ `special_plasma_slug` at damage −10% / ammo −100%, plus the `_cooled` rail-gun variant.
940
+
941
+ - **Files:** `blueprints.jsonc` (per-blueprint, per-grade stat modifiers),
942
+ `blueprint-costs.jsonc` (the matching per-grade material requirements),
943
+ `blueprint-journal-names.jsonc` (the three recipe ids whose journal spelling collides
944
+ with another recipe), `experimental-effects.jsonc` (special-effect stat modifiers and
945
+ qualitative descriptions), and `experimental-effect-costs.jsonc` (the matching
946
+ one-application material costs).
947
+ Stored modifier labels use journal `Modifier` **Labels**. Each blueprint is `{ name, grades }`
948
+ (each grade `{ features, damageDistribution? }`), with its cost file keyed by the same
949
+ blueprint and grade ids. Each experimental effect is
950
+ `{ name, modifiers, damageDistribution?, description? }`, with its cost file keyed by
951
+ the same effect ids.
952
+ - **Display names:** each blueprint and experimental effect carries its `name`.
953
+ Effect names are the English strings observed in-game. Blueprint names are coriolis
954
+ `blueprint.name` for the 81 blueprints coriolis carries, and the Operations dossier's
955
+ display label for the other 26 — the 25 Operations keys and `GuardianModule_Sturdy`,
956
+ which is journal-keyed but absent from coriolis, so its name comes from the Inara
957
+ registry like the Operations keys' own.
958
+ - **These are the short modifier labels, not the full outfitting-panel
959
+ strings — deliberately.** The panel calls `Weapon_LongRange` "Long-Range Weapon",
960
+ `ShieldBooster_HeavyDuty` "Heavy Duty Shield Booster" and
961
+ `Armour_Advanced` "Lightweight Armour"; this catalogue says "Long range", "Heavy
962
+ duty" and "Lightweight". Nearly all 81 differ that way, because a blueprint's name
963
+ is read next to the module it is applied to, where repeating the module's own name
964
+ is noise. The convention is house style and is kept: switching to the panel strings
965
+ would change every blueprint record's `name` for no gain. Two names were wrong in
966
+ their own right rather than short by convention, and take EDSY's spelling —
967
+ `CargoRack_IncreasedCapacity` is **"Expanded Cargo Rack"** (not "Expanded Capacity")
968
+ and `special_choke_canister` **"Ion Disruption"** (not "Ion Disruptor").
969
+ - **Blueprint journal names — three collisions, stored separately from mechanics.**
970
+ `blueprint-journal-names.jsonc` maps a recipe id only when the id the game writes for it
971
+ is a key some _other_ record already answers to. The other 104 need no entry for two
972
+ different reasons — 79
973
+ because their key already is the id a journal writes (including Anti-Guardian Zone
974
+ Resistance as `GuardianModule_Sturdy`), and 25 because they are Operations ids for
975
+ which no journal spelling has been observed — 21 of them recipes a module is sold
976
+ already carrying and four recipes a player rolls at an engineer. The three that do are
977
+ `Scanner_LongRange` and `Scanner_WideAngle`, coriolis keys
978
+ for recipes the game writes as `Sensor_LongRange` / `Sensor_WideAngle` — the same ids it
979
+ writes for the sensor suites' own Long Range and Wide Angle, which are different recipes
980
+ — and `MC_Overcharged`, its key for the multi-cannon Overcharged, which the game writes
981
+ as `Weapon_Overcharged` like every other weapon's. The map is deliberately **not** a
982
+ general alias mechanism: it says "the game writes this recipe as X", nothing about
983
+ equivalence, and contains exactly these three records. EDSY publishes the sensor-suite
984
+ and utility-scanner recipes as separate rows with different modifiers but the same
985
+ journal fdnames; its journal importer resolves them by module type. Coriolis supplies the
986
+ distinct stored recipe keys. The multi-cannon split is detailed under Engineering
987
+ options.
988
+ - **Blueprint source:** EDCD/coriolis-data,
989
+ `modifications/blueprints.json` (grade `features` + `components`) + `modifications.json`
990
+ (apply method), same commit as above. Each grade's `features` is a list of
991
+ `{ label, method, min, max }`; the modifier value is bounded
992
+ by the engineering quality roll (`v = min + (max − min)·quality`).
993
+ - **Material requirements** live on the same grade (`materials`), from that grade's
994
+ `components` map. Coriolis keys components by material **display name**; a join script
995
+ resolves each to the material's Frontier `symbol` against the `materials` domain at
996
+ generation time, emitting `{ symbol, name, count }` per requirement (join `symbol` to
997
+ `materials` for the material's own grade and category). **Kept as-is:**
998
+ `CargoRack_IncreasedCapacity` grade 5 has no components upstream, so its `materials`
999
+ is an empty list (the grade still resolves) rather than being dropped.
1000
+ - **Operations pre-engineered blueprints — from the in-game / Inara blueprint registry**
1001
+ (not in coriolis at the acquired commit): the Merc-Coin weapon rewards and the
1002
+ general/core/optional recipes (the **Operations keys**, e.g. `FuelScoop_Efficiency`,
1003
+ `MultiCannon_Rapid`) plus the Anti-Guardian recipe (grade 1 only).
1004
+ - **The registry's `recipe_` prefix is dropped.** Inara publishes these ids prefixed —
1005
+ `recipe_fuelscoop_efficiency`, `recipe_modulereinforcement_heavyduty` — but the prefix
1006
+ is an Inara listing convention, not part of the Frontier id. Neither menu registry
1007
+ uses it: coriolis's
1008
+ `modifications/blueprints.json` has **81 keys and not one prefixed**, and `eddb.js`
1009
+ contains no `recipe_` string at all (both checked 2026-08-07 UTC). Nor does real export
1010
+ data: a SLEF export contributed by the repository owner carries the Mercenary Module
1011
+ Reinforcement Package as **`modulereinforcement_heavyduty`** — the registry id minus
1012
+ the prefix, in the lower case Inara writes everything in — and across the 181-build
1013
+ corpus **not one of 1902 declared engineering entries is prefixed**. So the prefix is
1014
+ an Inara listing convention, and these keys are the id with it removed.
1015
+ - **The casing is Frontier's, taken from a raw journal.** Inara publishes these ids
1016
+ lower-case, but Inara lower-cases _every_ id it exports (`weapon_efficient`,
1017
+ `fsd_longrange`), so its casing says nothing. A raw `Loadout` event contributed by the
1018
+ repository owner (2026-08-07 UTC) settles it: the game writes `Armour_HeavyDuty`,
1019
+ `HullReinforcement_HeavyDuty`, `PowerDistributor_HighFrequency`, `Sensor_LightWeight`,
1020
+ `Misc_LightWeight`, `Weapon_HighCapacity` — PascalCase, with the compound words joined
1021
+ and each part capitalised. The Operations keys follow that, so
1022
+ `recipe_modulereinforcement_heavyduty` is `ModuleReinforcement_HeavyDuty` and
1023
+ `recipe_railgun_longshot` is `RailGun_LongShot`. Only the case was changed: no letter
1024
+ was added, removed or altered, and word boundaries come from each recipe's own display
1025
+ name ("Module Reinforcement Package — Heavy duty").
1026
+ - **Seven of these keys are almost certainly not journal ids in any casing.**
1027
+ `PowerDistributorS3C2_SupportFocused` and its four siblings, and
1028
+ `CargoRackS5C1_Extended` / `CargoRackS6C1_Extended`, embed a module size and class in
1029
+ the id. No blueprint Frontier writes is named that way — a journal spells the _module_
1030
+ `Int_CargoRack_Size5_Class1` and the _recipe_ separately. They read as Inara SKU ids
1031
+ for particular pre-engineered purchases. Dropping the prefix and casing them makes them
1032
+ consistent with their neighbours; it does not establish them as journal ids, and no
1033
+ observation covers them either way.
1034
+ - **No key keeps the `recipe_` prefix, including the Anti-Guardian ones.** Inara
1035
+ publishes that recipe twice — `recipe_guardianmodule_sturdy` and
1036
+ `recipe_guardianweapon_sturdy` — but its real name _is_ known,
1037
+ `GuardianModule_Sturdy`, so neither is a best guess at a journal id the way the other
1038
+ Operations keys are. Stripping the prefix makes the first of the two the real key
1039
+ itself and the second a weapon-side spelling of a recipe the game writes the module
1040
+ way on weapons too. Storing either as a second
1041
+ record of the same recipe is rejected: it is a copy that can drift from the one the
1042
+ game names, no observed journal, SLEF export or corpus build carries a prefixed id
1043
+ (see above), and nothing else in this catalogue keys one recipe twice.
1044
+
1045
+ The registry exposes **one displayed total per grade**, not a roll-bounded range, so each
1046
+ feature stores that total as a fixed value (`min == max`).
1047
+ The three Plasma conversion recipes also expose equal and opposite damage-share totals.
1048
+ Inara labels those player-facing rows **Thermal** and **Plasma**, not with journal
1049
+ modifier labels: Thermal decreases by 3.9, 6.6, 9.4, 12.4 and 15.5 percentage points
1050
+ across grades 1–5, while Plasma increases by the same amount. This library represents
1051
+ the resistance-ignoring ship-damage member as `absolute`, matching EDSY's `abswgt`
1052
+ **Absolute Damage** member; the contemporary community description credited in
1053
+ `ATTRIBUTIONS.md` likewise identifies this specific conversion's Plasma share as absolute
1054
+ damage, and is read as corroboration only — none of its text or media is redistributed.
1055
+ Because every eligible laser is 100% thermal before conversion, each grade stores the
1056
+ resulting `damageDistribution`: from 96.1/3.9 thermal/absolute at grade 1 through 84.5/15.5 at
1057
+ grade 5. Inara does not publish journal spellings for the damage members, and the
1058
+ repository contains no raw `Loadout` capture of this blueprint.
1059
+ Their per-roll `materials` are from the same registry (resolved to Frontier material
1060
+ `symbol`s against the `materials` domain); the per-roll **Merc-Coin** amount is also
1061
+ charged but is a currency, not a material, so it is not stored. Some totals are
1062
+ non-monotonic (pre-engineered UI values, not primitive weights — notably the
1063
+ Enduring-feedback rail-gun damage and the Balanced-distributor G4 mass) and are
1064
+ **preserved as published, not silently "corrected"**. The Merc-Coin **weapon-reward**
1065
+ recipes begin at grade 2 because the bought module already contains the grade-1
1066
+ pre-engineering; the general/core/optional recipes (fuel scoop, laser plasma-conversion)
1067
+ span grades 1–5, and the Anti-Guardian recipe is grade 1 only.
1068
+
1069
+ - **Anti-Guardian Zone Resistance is keyed once, as the game spells it.**
1070
+ `blueprints.jsonc` stores the one player-facing blueprint under
1071
+ **`GuardianModule_Sturdy`** — the id a journal writes, and the only one any engineering
1072
+ menu lists. It defines grade 1 only, exposes the `GuardianModuleResistance` activation
1073
+ Inara displays as +100%, and costs 2×`TG_Abrasion03`, 1×`TG_CausticCrystal`. Inara's
1074
+ `recipe_guardianmodule_sturdy` and `recipe_guardianweapon_sturdy` are that registry's
1075
+ spellings of this same recipe and are not stored beside it — see "No key keeps the
1076
+ `recipe_` prefix" above.
1077
+ - **The journal writes `GuardianModule_Sturdy`, on weapons as well as modules.** A
1078
+ `StoredModules` capture contributed by the repository owner (2026-08-07 UTC) carries a
1079
+ **Guardian Gauss Cannon** — a weapon — with `"EngineerModifications":
1080
+ "GuardianModule_Sturdy"`, `Level` 1. So the module spelling is what the game writes
1081
+ whichever kind of module the recipe sits on, and there is no evidence the game ever
1082
+ writes a weapon spelling: `recipe_guardianweapon_sturdy` is a registry key, not an
1083
+ observed journal one. EDSY names the blueprint `GuardianModule_Sturdy` for the same
1084
+ reason. `GuardianModule_Sturdy` is therefore the key all nine offering menus list.
1085
+ - **Anti-Guardian Zone Resistance and Plasma conversion are blueprints, not experimental
1086
+ effects.** The Anti-Guardian journal observation puts `GuardianModule_Sturdy` in the
1087
+ module's `EngineerModifications` / blueprint position with `Level` 1, and Inara publishes
1088
+ it as a grade-1 blueprint with a per-roll material recipe and no experimental-effect slot.
1089
+ Frontier's Operations update notes place **Thermal Plasma Conversion** under
1090
+ **Blueprints**, and the live Inara pages publish grades 1–5, per-roll materials and the
1091
+ ordinary laser experimental effects that can be applied alongside it. Consequently
1092
+ `special_guardian_module_resistance` and `special_plasma_rounds` are not incomplete
1093
+ effect identities: neither belongs in `experimental-effects.jsonc`. Frontier's
1094
+ Operations update-notes thread `648012` was acquired 2026-08-09 UTC; the page exposes
1095
+ no immutable revision.
1096
+ - **Experimental-effect source:** EDSY `eddb.js`
1097
+ `expeffect` is the primary source — one table holding each effect's modifiers and its
1098
+ recipe together, keyed the way the two local files are. `experimental-effects.jsonc`
1099
+ takes its `{ label, method, value }` modifiers; `experimental-effect-costs.jsonc` takes
1100
+ its `mats` map, resolved from EDSY's material short-codes to Frontier material `symbol`s
1101
+ against the `materials` domain and emitted as `{ symbol, name, count }`. An experimental
1102
+ effect is a single application, so that list is the whole material cost.
1103
+ - **Cross-checked against coriolis-data** (commit
1104
+ `0db9234b5b9ce8c939ea84133d7ce336eea88e27`, acquired 2026-08-01 UTC), which holds the
1105
+ same facts split across `modifications/modifierActions.json` (modifiers) and
1106
+ `modifications/specials.json` (recipes). All 86 active effects here appear in
1107
+ `specials.json`; **84** have a `modifierActions.json` entry to diff against — the two
1108
+ that do not, `special_blinding_shell` and `special_smart_rounds`, are qualitative
1109
+ records this file stores with no modifiers either. The two sources agree everywhere
1110
+ once each one's conventions are accounted for: coriolis stores the four resistances
1111
+ as `modmod` percentage points where this file stores fractions (hull and shield boost
1112
+ it stores as fractions, exactly as here — it is _EDSY_ that uses points for those),
1113
+ names a thruster's or drive's heat `thermload` where the journal Label is
1114
+ `EngineHeatRate` / `FSDHeatRate`, and inverts rate of fire as described above.
1115
+ The catalogue excludes rows that the source marks as withdrawn or comments out;
1116
+ they are not effects offered by a current engineering menu.
1117
+ - **What the two sources genuinely disagree on**, beyond the two coriolis-only legs
1118
+ noted above: EDSY gives `special_plasma_slug` and `special_plasma_slug_cooled` an
1119
+ `ammomax: -100` leg (stored here as `AmmoMaximum −1`, the "reloads from ship fuel"
1120
+ mechanic) that coriolis's `modifierActions` does not carry at all; and coriolis
1121
+ splits Plasma Slug by weapon family where EDSY does not, discussed next.
1122
+ - **Weapon-combat experimental effects are carried in full** — 29 of them (Auto Loader,
1123
+ Corrosive Shell, Force Shell, FSD Interrupt, Plasma Slug, …). A purely-qualitative one —
1124
+ a gameplay flag with no numeric magnitude the data exposes — carries an **empty
1125
+ `modifiers` list and a human-readable `description`** instead; effects that do have
1126
+ magnitudes carry them (e.g. Force Shell shot speed −16.6667%, FSD Interrupt damage −30%
1127
+ / burst interval +50%). A fixed damage-type conversion is carried separately as
1128
+ `damageDistribution`, because it is a nested split rather than a scalar modifier.
1129
+ Their one-application `materials` are from the same in-game / Inara registry (a
1130
+ Merc-Coin amount is also charged but is not stored). Every one is a weapon effect, and
1131
+ the weapon groups' menus list them.
1132
+ - **Three effects state a fixed converted damage type.** High Yield Shell, Inertial
1133
+ Impact and Overload Munitions produce 50/50 kinetic/explosive, kinetic/thermal and
1134
+ explosive/thermal respectively. Applying one replaces the weapon's conventional
1135
+ `damageDistribution`.
1136
+
1137
+ `journal-federation-corvette.jsonc` independently settles High Yield Shell, stating
1138
+ `$Kinetic;` 100 → 50 and `$Explosive;` 0 → 50 for its large gimballed cannon. The
1139
+ three sourced conversions remain a lower bound rather than a count:
1140
+ **eleven** of the 40 effects an engineer offers a weapon carry no `description` at all —
1141
+ `special_incendiary_rounds` and `special_emissive_munitions` among them — so for those
1142
+ the data neither states a conversion nor rules one out.
1143
+
1144
+ - **A pre-engineered `_cooled` variant carries its base effect's modifiers as well as the
1145
+ cut.** Each `_cooled` rail-gun variant is its base effect **plus** a −40% thermal load,
1146
+ so `special_feedback_cascade_cooled` carries damage −20%, `special_plasma_slug_cooled`
1147
+ damage −10% and ammo −100%, and `special_super_penetrator_cooled` reload +50% — all
1148
+ matching EDSY's `hrgx_*` entries, and `special_incendiary_rounds` its burst interval
1149
+ +5.2632%. Storing the thermal cut alone is the easy mistake here. Damage-**type** splits
1150
+ (kinetic/thermal/explosive weights) stay in `description` rather than `modifiers`, as
1151
+ they do for High Yield Shell and Inertial Impact.
1152
+ - **Journal Labels** for both sources are resolved via EDSY's own attribute table
1153
+ (`attr → fdattr`), the authority for the exact Label strings the game writes
1154
+ (e.g. coriolis `optmass` on an FSD → `FSDOptimalMass`, `maxfuel` → `MaxFuelPerJump`).
1155
+ Group-ambiguous keys (`optmass`, `optmul`, `thermload`) are disambiguated by the
1156
+ blueprint's target module group.
1157
+ - **The `Decorative_*` transformations EDSY lists are not blueprints, and are carried in
1158
+ `decorative-modifications.jsonc` instead.** They are real ids the game writes in the
1159
+ same field as a blueprint, and they name no recipe — see §Decorative modifications
1160
+ below for what they are and why they are stored apart.
1161
+ - **Blueprint keys deliberately left out:**
1162
+ - **Per-module-group aliases, not extra blueprints.** A blueprint that applies to several
1163
+ module groups is exposed once per group under a `recipe_sensor_<group>_<mod>`-style
1164
+ key whose display name points back at the canonical blueprint — for example the
1165
+ long-range sensor modification appears once for sensors and again for each scanner
1166
+ type. The blueprints they point at are already stored under their journal
1167
+ `BlueprintName`s (`Sensor_LongRange`, `Misc_LightWeight`, …). Storing the aliases would
1168
+ multiply one blueprint into many identical records. **Three keys are the exception and
1169
+ are not journal names**: `Scanner_LongRange` and `Scanner_WideAngle`, coriolis's split
1170
+ of a recipe the game writes as `Sensor_LongRange` / `Sensor_WideAngle`, and
1171
+ `MC_Overcharged`, its split of the one the game writes as `Weapon_Overcharged`. They
1172
+ are kept because each rolls different numbers from the record it shares a journal id
1173
+ with — the scanner side against the suite side, the multi-cannon's clip penalty against
1174
+ no penalty at all — and each has its journal spelling in the collision map. See the next bullet,
1175
+ and §Scanner Long Range and Wide Angle and §Multi-cannon Overcharged under Engineering
1176
+ options.
1177
+ - **Generic community-goal and tech-broker wrappers** ("Unique Modification", "Unique
1178
+ Enhancement") — reward placeholders that carry no grades or features.
1179
+ - **Effects with no published magnitude** are not stored with invented numbers. Where a
1180
+ qualitative effect _is_ published with a recipe it is carried with an empty `modifiers`
1181
+ list and a `description`, as described above; where neither a magnitude nor a recipe is
1182
+ published, it is left out entirely.
1183
+ - **Material costs:** `blueprint-costs.jsonc` preserves coriolis's material components per
1184
+ roll and grade; `experimental-effect-costs.jsonc` preserves EDSY's one-application
1185
+ recipes. Material display names are resolved against the materials domain while retaining
1186
+ the upstream Frontier symbols and counts.
1187
+
1188
+ ## Engineering options (what each module can take)
1189
+
1190
+ - **File:** `engineering-options.jsonc`.
1191
+ - **Availability is a property of the module, not of the blueprint.** A Pulse Laser and a
1192
+ Rail Gun both take the Efficient blueprint but offer different experimental effects, so
1193
+ "which experimentals go with blueprint X" has no single answer. Modules are therefore
1194
+ grouped (53 groups covering 1028 engineerable modules) and each group lists the
1195
+ `blueprints` and `experimentals` it offers.
1196
+ - **Source:** EDSY `eddb.js`, whose module-group tables carry each group's `blueprints`
1197
+ and `expeffects` lists and which modules belong to each group, and whose module records
1198
+ carry the per-module `noblueprints` / `noexpeffects`
1199
+ denials that narrow either list. Second registry: coriolis-data
1200
+ `modifications/modules.json`, which carries the same per-group lists keyed by the
1201
+ journal `BlueprintName`s this catalogue joins on.
1202
+ - **Coverage: every group EDSY's `mtype` table gives a `blueprints:` key.** That is 53
1203
+ groups over 1028 modules, including bulkheads (the 241 ship armour records), life
1204
+ support, sensors, the Detailed Surface Scanner, cargo racks, refineries, AFMUs, fuel
1205
+ scoops, FSD interdictors and boosters, Guardian module and shield reinforcement, the
1206
+ four engineerable limpet controllers, chaff, heat sink and caustic sink launchers,
1207
+ point defence, ECMs, the KWS/manifest/wake scanners, the Guardian Gauss/Plasma/Shard
1208
+ weapons, the AX missile racks and the Enzyme Missile Rack.
1209
+ - **A group is one menu, so `noblueprints` splits a family in two.** EDSY denies
1210
+ blueprints per module as well as per group (`edsy.js` `setBlueprintID` refuses a
1211
+ denied id; `'*'` means the module is not modifiable at all), and for three families
1212
+ the denial is a clean two-way split: a Guardian Power Plant is denied all three
1213
+ ordinary power-plant recipes and an ordinary one is denied Anti-Guardian Zone
1214
+ Resistance, and the same holds for the power distributors and the hull reinforcement
1215
+ packages. Those are stored as **two groups** — `powerPlants` /
1216
+ `guardianPowerPlants`, `powerDistributors` / `guardianPowerDistributors`,
1217
+ `hullReinforcements` / `guardianHullReinforcements` — rather than as a per-module
1218
+ exception, because a group _is_ a menu and these are two menus. Reading the
1219
+ registries alone would give the Guardian halves their ordinary twin's experimental
1220
+ list, since `expeffects` is published per group with no per-module denial on any of
1221
+ them; that they carry none is recorded further down, under "A Guardian module has no
1222
+ experimental slot".
1223
+ - **The ordinary halves must not list `GuardianModule_Sturdy`**, which is an
1224
+ Anti-Guardian recipe on a non-Guardian module and EDSY denies it. `powerPlants`,
1225
+ `powerDistributors` and `hullReinforcements` therefore hold ordinary modules only,
1226
+ and the 25 Guardian ones sit in the three groups above.
1227
+ - **14 modules are absent because upstream denies them every blueprint:** eight AX
1228
+ multi-cannons (all but the two gimballed), five of the seven mining tools, and the
1229
+ Mk II Plasma Shock Accelerator — which is why `antiXenoMultiCannons` holds 2 of that
1230
+ family's 10 modules, `miningToolsLasers` 2 of its 7 and `plasmaAccelerators` 4 of its 5.
1231
+ The ten plain Module Reinforcement Packages are denied their family's only recipe
1232
+ and are absent too, which leaves `moduleReinforcements` holding the ten Guardian
1233
+ packages.
1234
+ - **The 171 modules absent take no engineering.** Whole families first, both registries
1235
+ agreeing: fuel tanks, passenger cabins, the repair/recon/research/decontamination and
1236
+ multi-limpet controllers, meta-alloy and ordinary module reinforcement, the Pulse Wave
1237
+ Analyser, the mining launchers, Shock Cannons, Nanite Torpedo Pylons, fighter and
1238
+ vehicle hangars, the docking computers and Supercruise Assist, the module stabilisers,
1239
+ the planetary approach suites, the cargo hatch and
1240
+ the AX utility modules (Xeno Scanners, Shutdown Field Neutralisers), followed by the
1241
+ individually denied modules described above.
1242
+ - **EDSY's `_X_` prefix means "not applicable" and is honoured**, not stripped: the
1243
+ Detailed Surface Scanner's group lists only `iss_er` (`Sensor_Expanded`), because its
1244
+ three other entries are `_X_`-marked. The `Decorative_*` entries on the remote-release
1245
+ launchers are dropped for the same reason `blueprints.jsonc` does not carry them: a
1246
+ decorative transformation names no recipe, and no engineer applies one. So a
1247
+ launcher left with only those entries is offering nothing, and its `noblueprints`
1248
+ reading holds — carrying one already transformed is not the same as being
1249
+ engineerable. §Decorative modifications has the evidence.
1250
+ - **Where EDSY records one generic id and the journal writes a family-specific one,
1251
+ coriolis-data settles it.** EDSY collapses Lightweight, Reinforced and Shielded to
1252
+ `misc_lw` / `misc_rf` / `misc_sh` for eight families; coriolis keys the same lists by
1253
+ the journal `BlueprintName` this catalogue joins on, so life support lists
1254
+ `LifeSupport_LightWeight`, an AFMU `AFM_Shielded`, a fuel scoop `FuelScoop_Shielded`,
1255
+ a refinery `Refineries_Shielded` and each limpet controller its own. **This is not
1256
+ cosmetic for the scanners:** EDSY's `scan_lr` and `cs_lr` share the fdname
1257
+ `Sensor_LongRange`, but `Scanner_LongRange` is a different recipe (power draw, not
1258
+ mass; a larger range roll), so the utility scanners take the `Scanner_*` ids for Long
1259
+ Range and Wide Angle where the sensor suites take the `Sensor_*` ones. (Their other
1260
+ four ids are unaffected: `Sensor_FastScan` and the generic `Misc_*` trio, exactly as
1261
+ coriolis has them.) The shared fdname is not a defect in EDSY's table, and §Scanner
1262
+ Long Range and Wide Angle below is what follows from that. Eleven groups carry a
1263
+ substitution; the substituted lists are then checked against coriolis's own, as are
1264
+ the nine further groups it carries a list for —
1265
+ 20 in all, every one an exact match. Chaff, heat sink, point defence and ECMs keep the
1266
+ generic `Misc_*` ids: there coriolis agrees with EDSY.
1267
+ - **13 groups rest on EDSY alone**, because coriolis carries no blueprint list for
1268
+ them at all: the nine Guardian-only groups (`guardianPowerPlants`,
1269
+ `guardianPowerDistributors`, `guardianHullReinforcements`, `moduleReinforcements`,
1270
+ `shieldReinforcements`, `fsdBoosters`, `guardianGauss`, `guardianPlasma`,
1271
+ `guardianShard`), `antiXenoMissileRacks`, `experimentalWeapons`,
1272
+ `miningToolsLasers` and `antiXenoMultiCannons`. That is coriolis being
1273
+ silent rather than contradicting — its Guardian and anti-xeno groups are empty
1274
+ objects — but it means the second registry corroborates 40 of the 53 groups, not
1275
+ all of them. The Guardian-weapon menus are independently settled by the in-game
1276
+ observations below: stock weapons take Anti-Guardian Zone Resistance alone, while
1277
+ the pre-engineered articles are final.
1278
+ - **The multi-cannon Overcharged is the one place a group follows coriolis over EDSY.**
1279
+ EDSY has a single Overcharged for every weapon; coriolis splits it, and `multiCannons`
1280
+ lists coriolis's `MC_Overcharged`. `antiXenoMultiCannons` lists that key too, but not
1281
+ for that reason — coriolis carries no blueprint list for an anti-xeno group, so it is
1282
+ EDSY being followed into coriolis's spelling. See "Multi-cannon Overcharged: one
1283
+ journal id, two recipes" below for the evidence and for what the split costs.
1284
+ - **The groups name 86 of the 107 blueprints.** The other 21 are accounted for: they are
1285
+ Operations keys of modules sold already engineered rather than offered in a menu. Four
1286
+ Operations keys _are_ named by a group, because they are recipes a player applies — see
1287
+ "Four Operations recipes are listed by a menu" below.
1288
+ - **14 modules are bound by the family rule, not by a source row.** EDSY has no live
1289
+ entry for `Int_Hyperdrive_Size8_Class{1..5}` or `Int_ShieldGenerator_Size1_Class4`
1290
+ (both present but commented out, and both naming their `mtype` — `cfsd` and `isg`),
1291
+ nor for eight of the `*_free` starter fittings. Each takes its family's group, on the
1292
+ same rule the stats above use: a `*_free` variant is its priced twin bar the price,
1293
+ and a size-8 drive is a drive. `Int_FuelTank_Size1_Class3_free` is not bound because
1294
+ fuel tanks are not engineerable.
1295
+ - **Corpus evidence does not override `noblueprints`.** Two corpus builds declare
1296
+ `Weapon_Efficient` on the Mk II Plasma Shock Accelerator, while EDSY denies that module
1297
+ every blueprint (`noblueprints: {'*'}`). Coriolis publishes only the group-level menu
1298
+ and cannot settle the module-specific denial. The catalogue follows EDSY because a
1299
+ build declaration is not evidence that the blueprint can be applied in-game.
1300
+
1301
+ - **File order is derivable:** `modules` is written group by group in the order `groups`
1302
+ declares them, and within a group in module-catalogue order, so a re-derivation from the
1303
+ same sources reproduces the file rather than reshuffling it.
1304
+ - **`exclusions` are the exceptions, and they are real.** 24 modules take their group's
1305
+ blueprints but not all of its experimental effects: 13 Multi-cannons cannot take Phasing
1306
+ Sequence, six dumbfire racks cannot take Drag Munitions, four missile racks are short of
1307
+ Penetrator Munitions or FSD Interrupt, and the small fixed Abrasion Blaster takes none
1308
+ at all. Upstream these are an exclusion map (with a wildcard for "none of them"); here
1309
+ the wildcard is expanded to the explicit list. A module absent from `exclusions` takes
1310
+ its whole group's list. Five mining tools
1311
+ that would otherwise be listed here are absent from the catalogue entirely, taking no
1312
+ blueprint either.
1313
+ - **Kept deliberately:** the Abrasion Blaster stays in `modules` (it has a blueprint) even
1314
+ though its experimental list is empty. That distinction carries most of the catalogue:
1315
+ 30 of the 53 groups offer no experimental at all, so 388 of the 1028 grouped modules
1316
+ have an empty experimental list while retaining blueprints.
1317
+ - **Key form:** the Anti-Guardian blueprint is listed under `GuardianModule_Sturdy`, the id
1318
+ a Loadout writes and the one EDSY uses — the same and only spelling `blueprints.jsonc`
1319
+ keys it under.
1320
+ - **Anti-Guardian Zone Resistance carries no experimental effect.** All nine groups
1321
+ offering `GuardianModule_Sturdy` store `"experimentals": []`, including
1322
+ `guardianGauss`, `guardianPlasma` and `guardianShard`.
1323
+ - There are no pre-engineered Guardian module reward variants. The seven Guardian
1324
+ variants are weapons, whose ordinary recipes identify final purchases rather than
1325
+ engineer rolls.
1326
+ - **Neither registry publishes this, and a re-derivation will not reproduce it.**
1327
+ `expeffects` is published **per module group** by both — EDSY has no per-blueprint
1328
+ field and coriolis-data's `specials` sits beside `blueprints` rather than inside one —
1329
+ so a group offering exactly one blueprint still names the whole family's effects, and
1330
+ nothing in either file says a Guardian menu is narrower. Read EDSY alone and the three
1331
+ Guardian groups come back carrying their ordinary twin's list. This is a game fact
1332
+ recorded here, and it has to be reapplied after any re-derivation.
1333
+ - **Source:** a maintainer report of the in-game engineering menu, recorded 2026-08-07
1334
+ UTC — the same standing as the module-price and restricted-mount observations recorded
1335
+ above. There is no upstream
1336
+ revision to pin, because no registry publishes the fact; neither contradicts the
1337
+ report either, both being silent.
1338
+ - **The corpus neither corroborates nor contradicts the Guardian-module families.** None
1339
+ of the build corpus's 1902 declared engineering entries engineers a
1340
+ Guardian power plant, distributor or hull reinforcement package at all. Its
1341
+ Guardian-weapon entries are final pre-engineered articles, a separate case recorded
1342
+ below.
1343
+ - The 25 modules in the three split families above (`guardianPowerPlants`,
1344
+ `guardianPowerDistributors` and `guardianHullReinforcements`) therefore carry no
1345
+ experimental effects in the catalogue at all. Blueprints are unaffected on every
1346
+ module.
1347
+ - **Multi-cannon Overcharged uses a distinct stored key.** The `multiCannons` and
1348
+ `antiXenoMultiCannons` menus list `MC_Overcharged`; other weapon menus list
1349
+ `Weapon_Overcharged`. Coriolis `modifications/modules.json` assigns the first key to
1350
+ multi-cannons and the second to six other weapon groups, while
1351
+ `modifications/blueprints.json` gives both the journal fdname
1352
+ `Weapon_Overcharged`. The recipes differ only in the `AmmoClipSize` reduction carried
1353
+ by `MC_Overcharged` (−3% at grade 1 through −15% at grade 5).
1354
+ `modifications/blueprints.json` was acquired 2026-08-07 UTC and has SHA-256
1355
+ `cba5a11fc7728e0d1da63fcbbc8d9dfedf9fbc51c99692ee187c7bf0293b3fa1`.
1356
+ - EDSY uses one `wpn_oc` recipe and includes the clip reduction on every listed
1357
+ multi-cannon group. Coriolis has no AX multi-cannon menu, so the AX binding combines
1358
+ EDSY's group coverage with coriolis's key for the clip-bearing recipe.
1359
+ - Frontier journal captures independently show `Weapon_Overcharged` without an
1360
+ `AmmoClipSize` modifier on a large gimballed cannon
1361
+ (`journal-federation-corvette.jsonc`), a medium fixed fragment cannon
1362
+ (`journal-federation-corvette-plasma.jsonc`) and a medium fixed plasma accelerator
1363
+ (`journal-caspian-explorer.jsonc`). Their recorded grades, qualities and other
1364
+ modifier legs reproduce the published recipe values. EDEngineer's
1365
+ `blueprints.json` likewise assigns the clip reduction to multi-cannon types and not
1366
+ to cannon, fragment-cannon or plasma-accelerator types.
1367
+ - The two Merc-Coin AX multi-cannon rows in `pre-engineered.jsonc` use
1368
+ `MC_Overcharged`, matching the menu binding and the clip-bearing recipe.
1369
+ - **An ordinary recipe on a Guardian weapon identifies a final purchase, not an engineer
1370
+ roll.** The three Guardian weapon groups list **only** Anti-Guardian Zone Resistance,
1371
+ exactly as the six Guardian _module_ groups do. `Weapon_RapidFire` on `guardianGauss`,
1372
+ `Weapon_Overcharged` on `guardianPlasma` and `Weapon_LongRange` on `guardianShard`
1373
+ describe sold variants, not recipes a player can roll at an engineer. The bought or
1374
+ awarded articles are final: unlike their stock counterparts, they cannot even take
1375
+ Anti-Guardian Zone Resistance. Two independent bodies of real data and the repository
1376
+ owner's in-game verification (2026-08-09 UTC; no immutable revision) support that
1377
+ distinction:
1378
+ - A 521-module `StoredModules` capture (2026-08-07 UTC) holds **20** Guardian weapons
1379
+ carrying an ordinary recipe. Every one is a **Fixed Small or Fixed Medium** variant that
1380
+ `pre-engineered.jsonc` already records as _sold_ carrying that exact recipe. No Large
1381
+ and no Turret variant carries one, and exactly one Guardian weapon in the whole capture
1382
+ carries `GuardianModule_Sturdy` — the only recipe a player can actually roll onto it.
1383
+ - The 181-build community corpus adds **18** final articles: 5× and 2× Guardian Plasma
1384
+ Launcher Fixed Medium/Small with `Weapon_Overcharged`, 6× Guardian Shard Cannon Fixed
1385
+ Medium with `Weapon_LongRange` and `special_super_penetrator_cooled`, and 5× Guardian
1386
+ Gauss Cannon Fixed Medium with `Weapon_HighCapacity`. The declarations describe the
1387
+ pre-engineered articles as exported by the build tools; they do not expand either
1388
+ stock weapon's engineering menu.
1389
+
1390
+ So these recipes reach the weapons only as **pre-engineered identities**, and no menu
1391
+ lists them: `pre-engineered.jsonc` marks all seven catalogued Guardian-weapon variants
1392
+ `engineeringLocked: true`, and the 18 build-corpus entries that name one are final
1393
+ articles rather than recipes a player may apply.
1394
+
1395
+ - **Four Operations recipes appear in engineering menus:** `FuelScoop_Efficiency` on
1396
+ `fuelScoops`, plus `PulseLaser_ThermalPlasmaConversion`,
1397
+ `BurstLaser_ThermalPlasmaConversion` and `BeamLaser_ThermalPlasmaConversion` on their
1398
+ respective laser groups. Inara publishes these as grades 1–5 with per-roll material and
1399
+ Merc-Coin costs, distinguishing them from the grade-2–5 reward recipes. The recipe names
1400
+ identify the module families, and their modifier fields match those families. The live
1401
+ Inara pages were acquired 2026-08-09 UTC; no immutable revision is exposed.
1402
+
1403
+ ## Decorative modifications
1404
+
1405
+ - **File:** `decorative-modifications.jsonc`. Three records —
1406
+ `Decorative_Green`, `Decorative_Red`, `Decorative_Yellow` — each
1407
+ `{ name, modules, modifiers }`.
1408
+ - **Source:** a `StoredModules` capture contributed by the repository owner
1409
+ (521 stored modules, 2026-08-07 UTC) holds three medium turreted Remote Release Flak
1410
+ Launchers, one per colour, in `EngineerModifications`. Those three are the only ones of
1411
+ the capture's 46 distinct spellings that name no recipe: every other spelling, down to
1412
+ the lower-case `weapon_longrange` the game writes on a Guardian Shard Cannon, resolves
1413
+ against the blueprint catalogue. They have no grade, material cost or applying engineer,
1414
+ so they are transformations rather than blueprint recipes.
1415
+ - **They are not cosmetic-only: each carries a −99% `Damage` modifier.** A festive launcher
1416
+ fires fireworks rather than flak. The repository owner's outfitting panel reads −99.0%,
1417
+ 0.3 damage and 0.2 damage/s. The medium turreted launcher's 34 base damage becomes 0.34,
1418
+ displayed as 0.3; at 0.5 shots/s that becomes 0.17, displayed as 0.2/s. An overwrite to
1419
+ 0.3 would instead display 0.1/s, so the stored method is multiplicative. EDSY lists the
1420
+ transformations but omits this modifier.
1421
+ - **Engineering availability:** the launchers were awarded already transformed; no
1422
+ engineer applies the transformation. The acquisition route is the contributor's
1423
+ account, not a field in the capture.
1424
+ - **`modules` is what has been observed, not what the game permits.** The medium turreted
1425
+ Remote Release Flak Launcher (`Hpt_FlakMortar_Turret_Medium`) is the only module any
1426
+ capture shows carrying a decorative transformation, so it is the only symbol stored.
1427
+ - **`name` pairs the festive naming with the id's colour** — `"Festive Green"`,
1428
+ `"Festive Red"`, `"Festive Yellow"`. No registry publishes the outfitting panel's own
1429
+ string: EDSY carries the transformation, not a label. These names come from the
1430
+ repository owner's account.
1431
+
1432
+ ## Pre-engineered modules
1433
+
1434
+ - **File:** `pre-engineered.jsonc`.
1435
+ - **Guardian coverage is complete.** There are no pre-engineered Guardian power plant,
1436
+ distributor, hull-reinforcement, module-reinforcement, shield-reinforcement or
1437
+ FSD-booster reward variants, so the absence of an `Int_Guardian*` row is deliberate. The
1438
+ catalogue's seven Guardian rows are all weapons (Gauss, Plasma and Shard), each with a
1439
+ `blueprint` and no `experimental`. Source: maintainer confirmation recorded 2026-08-12
1440
+ UTC; there is no immutable upstream revision.
1441
+ - **Records:** pair a base module `symbol` with its published pre-engineered identity:
1442
+ `{ symbol, name, blueprint, grade, acquisition }`, plus any sourced stat block and
1443
+ price. The game reports these articles under the base module symbol rather than a
1444
+ distinct variant symbol.
1445
+ - **`acquisition` says where a variant comes from.** 73 records: 22 `mercenary`,
1446
+ 30 `communityGoal` and 21 `techBroker`.
1447
+ - **`mercenary`** — the Merc-Coin shop rows. Source: the in-game outfitting and
1448
+ blueprint registries, cross-checked against Inara's outfitting and blueprint registries
1449
+ acquired 2026-08-07 UTC (no immutable revision exposed) and Frontier's update notes.
1450
+ All 22 are grade 1, and that is the point: the
1451
+ purchased module already
1452
+ contains the grade-1 pre-engineering, which is exactly why these blueprints' own
1453
+ recipes start at grade 2 (see the Operations section above). The two facts are
1454
+ consistent by construction: material costs for further engineering begin at grade 2.
1455
+ - **The large Seeker Missile Rack's Lockdown** is a `mercenary` row on
1456
+ `Hpt_BasicMissileRack_Fixed_Large` at **900 MC**, taking the shop total to 13 900 MC.
1457
+ Four things agree, none of them a guess about a module symbol: the registry keys
1458
+ Lockdown by _size_ and the twin `SeekerMissileRackMedium_Lockdown` binds to the medium
1459
+ rack; the large rack is already a Merc row for `SeekerMissileRack_Drag`, so the shop
1460
+ stocks it; both Lockdown recipes run grades 2–5, the weapon-reward range that marks a
1461
+ module as bought pre-engineered; and it is the only grade-2–5 Operations recipe in the
1462
+ file
1463
+ that would otherwise have no row, all 20 others having one. Price and size confirmed
1464
+ 2026-08-07 UTC against an index of the Inara outfitting listing, which
1465
+ reports the MERC Lockdown Seeker Missile Rack [Fixed] at 900 MC for the 3A and 800 MC
1466
+ for the 2B. This is an index reading rather than a pinned page capture. Both halves check
1467
+ against rows already here — the large rack is 3A and its other Merc row is 900 MC, the
1468
+ medium is 2B and its Lockdown row is 800 MC — and that corroboration is what carries
1469
+ the weight.
1470
+ - **`communityGoal`** — modules awarded for taking part in a community goal. Source:
1471
+ EDSY's stored-module presets, which record each reward as an encoded module state; the
1472
+ blueprint, grade and experimental effect were
1473
+ decoded from that state rather than inferred from its display label. All ids join to
1474
+ the blueprint, experimental-effect and module catalogues. 28 of the 30 are grade 5;
1475
+ 8 carry an experimental effect. Acquired 2026-08-01 UTC.
1476
+ - **`techBroker`** — modules unlocked at a tech broker, from the same EDSY presets and
1477
+ decoded the same way. Human brokers stock the "V1" drives, the SCO drives and a
1478
+ seeker rack; the Guardian weapon rows come from the Salvation, Azimuth and Sirius
1479
+ brokers. 14 of the 21 are grade 5 — the seven grade-1 rows are the Guardian weapons
1480
+ and a heat sink launcher, where the blueprint named does define a grade 1, so the
1481
+ grade is a real grade of a real recipe rather than the Merc-shop convention.
1482
+ Acquired 2026-08-01 UTC.
1483
+ - **One route per row, not every route.** The source records a single tag per preset
1484
+ and several rows are annotated as having been obtainable both ways — the six SCO "V1"
1485
+ drives most obviously. `acquisition` records the tag; it is not a claim that no other
1486
+ route ever existed.
1487
+ - **`engineeringLocked: true` marks all seven pre-engineered Guardian-weapon rows as
1488
+ final.** The source and capture evidence are recorded once under Engineering options.
1489
+ - **A reward variant is not reproducible by engineering the same blueprint.** Alongside
1490
+ its blueprint and effect, each reward carries hand-set modifier overrides no blueprint
1491
+ grants — that is what makes it a reward rather than a shortcut. The `blueprint` /
1492
+ `grade` / `experimental` recorded here **identify** the variant; they are not a recipe
1493
+ that recreates it. The ordinary blueprint material recipe does not price the reward.
1494
+ - **Two community-goal rewards are not stored:** the size-5 and size-6 Corrosion
1495
+ Resistant Cargo Racks carry no engineering at all. They already exist as ordinary
1496
+ module records (`Int_CorrosionProofCargoRack_Size{5,6}_Class1`), so there is no pairing
1497
+ to record.
1498
+ - **`mercCoinCost` is the shop price in Merc Coin**, on the 22 `mercenary` rows and
1499
+ nowhere else. Source: the in-game outfitting registry, with the variants and prices
1500
+ corroborated by Inara's outfitting registry acquired 2026-08-07 UTC; no immutable
1501
+ revision is exposed.
1502
+ Merc Coin is a separate currency with no credit equivalent, which is why it is its own
1503
+ field rather than the `cost` modules carry. Tech-broker unlocks have no equivalent
1504
+ number: they are paid in materials and commodities, so nothing is stored for them.
1505
+ - **`modifiers` is the hand-set stat block a reward variant arrives with** — what makes
1506
+ these records fittable rather than merely catalogued. Same vocabulary as a blueprint
1507
+ feature: a journal Modifier `label`, a `method` (`multiplicative` / `additive` /
1508
+ `overwrite`) and a `value`. Decoded from the same EDSY preset state as the blueprint
1509
+ and grade, then translated into the Almanac's own vocabulary — EDSY's attribute names
1510
+ map to journal Modifier Labels through its own table, and resistances, which EDSY
1511
+ stores in a different form from this repo, are converted using the module's base
1512
+ resistance. 51 rows carry one; the 22 `mercenary` rows do not, because no registry
1513
+ publishes the grade-1 pre-engineering they arrive with and a guess is worse than an
1514
+ omission.
1515
+ - **Values are the authored decimals, recovered rather than rounded.** The presets
1516
+ encode modifiers in EDSY's custom 20-bit float (1 sign, 5 exponent, 14 mantissa),
1517
+ which carries about fifteen significant bits — so decoding a change the game states
1518
+ as `+20%` yields `0.199997`. Rounding that by eye would be a guess, so instead each
1519
+ value is the **shortest decimal that re-encodes to the identical 20 bits**: the
1520
+ figure the encoder was originally given, checked by re-encoding rather than assumed.
1521
+ All 51 stat blocks recover exactly; a value with no short round-tripping form would
1522
+ have been kept as decoded, and none needed it. This is what makes the 5A "FSD V1"
1523
+ resolve to a whole 1785 optimal mass (from `+0.7`) instead of 1785.0126 (from
1524
+ `0.699988`).
1525
+ - **…except where the game authored a _stat_, not a multiplier.** Recovering the
1526
+ multiplier is the right move only when a multiplier is what was written down. The
1527
+ tech-broker "Modified Guardian Shard Cannon" is 3000 m range with falloff from
1528
+ 1500 m — round numbers — but no short multiplier on a 1700 m base reproduces them, so
1529
+ the best recovery still read 2999.99 m and 1499.995 m. These are found with the same
1530
+ round-trip discipline applied one level up: round the **resulting stat**, derive the
1531
+ multiplier it implies, and re-encode. Where that lands on the stored bits (within the
1532
+ encoder's own one-unit rounding), the source cannot tell the two apart and the round
1533
+ stat is what was authored, so it is stored as an **`overwrite` of the stat** — exact,
1534
+ and the shape a journal reports a pre-engineered modifier in anyway. **14 modifiers**
1535
+ across 7 modules are stored this way, and the file holds 20 `overwrite` modifiers
1536
+ over 11 modules in all.
1537
+ Worth stating plainly, because the blueprint name invites the opposite reading: the
1538
+ Shard's `MaximumRange` ×1.7647 with `FalloffRange` ×0.88235 is **not** a Long Range
1539
+ roll of any grade. It is a bespoke stat block, as every reward variant's is.
1540
+ Frontier's `journal-anaconda-slapaconda.jsonc` capture directly reads the medium
1541
+ variant's projectile speed as 6299.208984 m/s. The stored overwrite is the authored
1542
+ decimal **6299.209 m/s**, with the journal residue treated as float noise, instead of
1543
+ EDSY's 3568.6 m/s preset-derived result for that field. The fixed-medium
1544
+ base damage of 3.7235 reproduces the same article's panel without a separate damage
1545
+ modifier: it displays as 3.7, and its 12 projectiles at 1.666667 shots/s display as
1546
+ 74.5 damage/s.
1547
+ - **The guard that matters:** an `overwrite` is absolute, so it is only applied where
1548
+ _this repo's_ base agrees with the one the stat was inverted against. The Guardian
1549
+ Gauss Cannon's damage fails that check and stays multiplicative. EDSY's preset uses
1550
+ stock damage 40 / 70 for the small / medium cannons; current in-game module panels
1551
+ read 22 / 38.5, which the module catalogue now stores. Converting EDSY's resulting
1552
+ stat to an overwrite would therefore import its disproved stock value under cover of
1553
+ a rounding fix. The relative quarter-damage transformation remains usable without
1554
+ doing that; an absolute value would require a reading of the pre-engineered article
1555
+ itself.
1556
+ - **Burst interval has to be added to the decoder's output by hand.** EDSY carries no
1557
+ journal Label for `bstint` — the journal reports the resulting `RateOfFire`, never the
1558
+ interval it comes from — so a straight decode drops it, leaving the 13 variants that
1559
+ change a burst pattern on the _stock_ cadence, and four of them (the two frag cannons
1560
+ and the two Guardian gauss cannons) inconsistent as well as slow, carrying the
1561
+ engineered `BurstSize` — and, on the gauss cannons, the engineered `BurstRateOfFire` —
1562
+ against a stock interval. All 13 are stored under **`BurstInterval`**, the same label
1563
+ the Rapid Fire and High Capacity blueprint features use (see the Engineering section
1564
+ above), and it is the file's one departure from what the decoder emits: re-running the
1565
+ decoder over the same EDSY revision reproduces every other byte.
1566
+ - **Where the two references disagree about a pre-engineered weapon, this file follows
1567
+ EDSY.** coriolis models 29 pre-engineered modules as separate module records with
1568
+ their own observed stats rather than as modifiers, so the two can be compared. On the
1569
+ medium rail gun and the medium multi-cannon they agree within about 10% (0.3225 s
1570
+ against 0.36 s, 0.100 s against 0.1115 s). On the Guardian gauss cannons they do not:
1571
+ EDSY gives a four-round burst at 10 /s on a 0.5126 s interval with a quarter of the
1572
+ stock damage, thermal load and distributor draw, and coriolis a single shot on a
1573
+ 1.15 s interval at reduced damage (9.6 on the small, 18.3 on the medium) with
1574
+ **stock** thermal load and distributor draw. Since
1575
+ the pre-engineered gauss cannon's defining property is that it runs cool, coriolis's
1576
+ record looks like the incomplete one; EDSY's also conserves the stock weapon's damage
1577
+ per cycle, which coriolis's does not. The two sources also disagree on the variant's
1578
+ damage, clip size and ammunition, independently of the restored interval.
1579
+ - **Not included:** engineered modules that are one-off mission or salvage rewards rather
1580
+ than a repeatable outfitting row. They have no stable catalogue row.