@its-not-rocket-science/ananke 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (311) hide show
  1. package/CHANGELOG.md +135 -0
  2. package/LICENSE +21 -0
  3. package/README.md +2199 -0
  4. package/STABLE_API.md +266 -0
  5. package/dist/src/anatomy/anatomy-compiler.d.ts +14 -0
  6. package/dist/src/anatomy/anatomy-compiler.js +277 -0
  7. package/dist/src/anatomy/anatomy-contracts.d.ts +94 -0
  8. package/dist/src/anatomy/anatomy-contracts.js +1 -0
  9. package/dist/src/anatomy/anatomy-helpers.d.ts +82 -0
  10. package/dist/src/anatomy/anatomy-helpers.js +233 -0
  11. package/dist/src/anatomy/anatomy-schema.d.ts +28 -0
  12. package/dist/src/anatomy/anatomy-schema.js +388 -0
  13. package/dist/src/anatomy/index.d.ts +4 -0
  14. package/dist/src/anatomy/index.js +4 -0
  15. package/dist/src/archetypes.d.ts +87 -0
  16. package/dist/src/archetypes.js +285 -0
  17. package/dist/src/arena.d.ts +173 -0
  18. package/dist/src/arena.js +695 -0
  19. package/dist/src/bridge/bridge-engine.d.ts +46 -0
  20. package/dist/src/bridge/bridge-engine.js +252 -0
  21. package/dist/src/bridge/index.d.ts +4 -0
  22. package/dist/src/bridge/index.js +5 -0
  23. package/dist/src/bridge/interpolation.d.ts +64 -0
  24. package/dist/src/bridge/interpolation.js +130 -0
  25. package/dist/src/bridge/mapping.d.ts +33 -0
  26. package/dist/src/bridge/mapping.js +54 -0
  27. package/dist/src/bridge/types.d.ts +94 -0
  28. package/dist/src/bridge/types.js +2 -0
  29. package/dist/src/campaign.d.ts +141 -0
  30. package/dist/src/campaign.js +235 -0
  31. package/dist/src/channels.d.ts +15 -0
  32. package/dist/src/channels.js +20 -0
  33. package/dist/src/chronicle.d.ts +124 -0
  34. package/dist/src/chronicle.js +232 -0
  35. package/dist/src/collective-activities.d.ts +154 -0
  36. package/dist/src/collective-activities.js +247 -0
  37. package/dist/src/competence/acoustic.d.ts +101 -0
  38. package/dist/src/competence/acoustic.js +242 -0
  39. package/dist/src/competence/catalogue.d.ts +30 -0
  40. package/dist/src/competence/catalogue.js +241 -0
  41. package/dist/src/competence/crafting.d.ts +35 -0
  42. package/dist/src/competence/crafting.js +88 -0
  43. package/dist/src/competence/engineering.d.ts +53 -0
  44. package/dist/src/competence/engineering.js +108 -0
  45. package/dist/src/competence/framework.d.ts +68 -0
  46. package/dist/src/competence/framework.js +694 -0
  47. package/dist/src/competence/index.d.ts +12 -0
  48. package/dist/src/competence/index.js +13 -0
  49. package/dist/src/competence/interspecies.d.ts +81 -0
  50. package/dist/src/competence/interspecies.js +108 -0
  51. package/dist/src/competence/language.d.ts +79 -0
  52. package/dist/src/competence/language.js +115 -0
  53. package/dist/src/competence/naturalist.d.ts +97 -0
  54. package/dist/src/competence/naturalist.js +187 -0
  55. package/dist/src/competence/navigation.d.ts +24 -0
  56. package/dist/src/competence/navigation.js +48 -0
  57. package/dist/src/competence/performance.d.ts +125 -0
  58. package/dist/src/competence/performance.js +210 -0
  59. package/dist/src/competence/teaching.d.ts +64 -0
  60. package/dist/src/competence/teaching.js +121 -0
  61. package/dist/src/competence/willpower.d.ts +74 -0
  62. package/dist/src/competence/willpower.js +114 -0
  63. package/dist/src/crafting/index.d.ts +55 -0
  64. package/dist/src/crafting/index.js +229 -0
  65. package/dist/src/crafting/manufacturing.d.ts +83 -0
  66. package/dist/src/crafting/manufacturing.js +165 -0
  67. package/dist/src/crafting/materials.d.ts +53 -0
  68. package/dist/src/crafting/materials.js +120 -0
  69. package/dist/src/crafting/recipes.d.ts +75 -0
  70. package/dist/src/crafting/recipes.js +233 -0
  71. package/dist/src/crafting/workshops.d.ts +61 -0
  72. package/dist/src/crafting/workshops.js +170 -0
  73. package/dist/src/debug.d.ts +86 -0
  74. package/dist/src/debug.js +76 -0
  75. package/dist/src/derive.d.ts +21 -0
  76. package/dist/src/derive.js +88 -0
  77. package/dist/src/describe.d.ts +29 -0
  78. package/dist/src/describe.js +276 -0
  79. package/dist/src/dialogue.d.ts +122 -0
  80. package/dist/src/dialogue.js +266 -0
  81. package/dist/src/dist.d.ts +20 -0
  82. package/dist/src/dist.js +39 -0
  83. package/dist/src/downtime.d.ts +89 -0
  84. package/dist/src/downtime.js +391 -0
  85. package/dist/src/economy.d.ts +116 -0
  86. package/dist/src/economy.js +182 -0
  87. package/dist/src/emotional-contagion.d.ts +142 -0
  88. package/dist/src/emotional-contagion.js +274 -0
  89. package/dist/src/equipment.d.ts +206 -0
  90. package/dist/src/equipment.js +598 -0
  91. package/dist/src/faction.d.ts +102 -0
  92. package/dist/src/faction.js +237 -0
  93. package/dist/src/generate.d.ts +35 -0
  94. package/dist/src/generate.js +166 -0
  95. package/dist/src/index.d.ts +42 -0
  96. package/dist/src/index.js +54 -0
  97. package/dist/src/inheritance.d.ts +69 -0
  98. package/dist/src/inheritance.js +136 -0
  99. package/dist/src/inventory.d.ts +194 -0
  100. package/dist/src/inventory.js +637 -0
  101. package/dist/src/item-durability.d.ts +69 -0
  102. package/dist/src/item-durability.js +308 -0
  103. package/dist/src/legend.d.ts +97 -0
  104. package/dist/src/legend.js +269 -0
  105. package/dist/src/lod.d.ts +9 -0
  106. package/dist/src/lod.js +84 -0
  107. package/dist/src/metrics.d.ts +51 -0
  108. package/dist/src/metrics.js +91 -0
  109. package/dist/src/model3d.d.ts +138 -0
  110. package/dist/src/model3d.js +214 -0
  111. package/dist/src/mythology.d.ts +101 -0
  112. package/dist/src/mythology.js +308 -0
  113. package/dist/src/narrative-render.d.ts +42 -0
  114. package/dist/src/narrative-render.js +194 -0
  115. package/dist/src/narrative-stress.d.ts +123 -0
  116. package/dist/src/narrative-stress.js +183 -0
  117. package/dist/src/narrative.d.ts +44 -0
  118. package/dist/src/narrative.js +257 -0
  119. package/dist/src/party.d.ts +70 -0
  120. package/dist/src/party.js +226 -0
  121. package/dist/src/polity.d.ts +262 -0
  122. package/dist/src/polity.js +398 -0
  123. package/dist/src/presets.d.ts +42 -0
  124. package/dist/src/presets.js +170 -0
  125. package/dist/src/progression.d.ts +170 -0
  126. package/dist/src/progression.js +256 -0
  127. package/dist/src/quest-generators.d.ts +76 -0
  128. package/dist/src/quest-generators.js +534 -0
  129. package/dist/src/quest.d.ts +239 -0
  130. package/dist/src/quest.js +520 -0
  131. package/dist/src/relationships-effects.d.ts +75 -0
  132. package/dist/src/relationships-effects.js +219 -0
  133. package/dist/src/relationships.d.ts +104 -0
  134. package/dist/src/relationships.js +347 -0
  135. package/dist/src/replay.d.ts +47 -0
  136. package/dist/src/replay.js +82 -0
  137. package/dist/src/rng.d.ts +9 -0
  138. package/dist/src/rng.js +37 -0
  139. package/dist/src/settlement-services.d.ts +67 -0
  140. package/dist/src/settlement-services.js +267 -0
  141. package/dist/src/settlement.d.ts +143 -0
  142. package/dist/src/settlement.js +419 -0
  143. package/dist/src/sim/action.d.ts +28 -0
  144. package/dist/src/sim/action.js +12 -0
  145. package/dist/src/sim/aging.d.ts +95 -0
  146. package/dist/src/sim/aging.js +243 -0
  147. package/dist/src/sim/ai/decide.d.ts +10 -0
  148. package/dist/src/sim/ai/decide.js +267 -0
  149. package/dist/src/sim/ai/perception.d.ts +12 -0
  150. package/dist/src/sim/ai/perception.js +54 -0
  151. package/dist/src/sim/ai/personality.d.ts +54 -0
  152. package/dist/src/sim/ai/personality.js +202 -0
  153. package/dist/src/sim/ai/presets.d.ts +2 -0
  154. package/dist/src/sim/ai/presets.js +28 -0
  155. package/dist/src/sim/ai/system.d.ts +6 -0
  156. package/dist/src/sim/ai/system.js +13 -0
  157. package/dist/src/sim/ai/targeting.d.ts +8 -0
  158. package/dist/src/sim/ai/targeting.js +42 -0
  159. package/dist/src/sim/ai/types.d.ts +14 -0
  160. package/dist/src/sim/ai/types.js +1 -0
  161. package/dist/src/sim/body.d.ts +9 -0
  162. package/dist/src/sim/body.js +32 -0
  163. package/dist/src/sim/bodyplan.d.ts +161 -0
  164. package/dist/src/sim/bodyplan.js +677 -0
  165. package/dist/src/sim/capability.d.ts +135 -0
  166. package/dist/src/sim/capability.js +8 -0
  167. package/dist/src/sim/combat.d.ts +21 -0
  168. package/dist/src/sim/combat.js +77 -0
  169. package/dist/src/sim/commandBuilders.d.ts +11 -0
  170. package/dist/src/sim/commandBuilders.js +39 -0
  171. package/dist/src/sim/commands.d.ts +71 -0
  172. package/dist/src/sim/commands.js +8 -0
  173. package/dist/src/sim/condition.d.ts +35 -0
  174. package/dist/src/sim/condition.js +21 -0
  175. package/dist/src/sim/cone.d.ts +40 -0
  176. package/dist/src/sim/cone.js +44 -0
  177. package/dist/src/sim/context.d.ts +68 -0
  178. package/dist/src/sim/context.js +1 -0
  179. package/dist/src/sim/density.d.ts +14 -0
  180. package/dist/src/sim/density.js +33 -0
  181. package/dist/src/sim/disease.d.ts +141 -0
  182. package/dist/src/sim/disease.js +353 -0
  183. package/dist/src/sim/entity.d.ts +251 -0
  184. package/dist/src/sim/entity.js +19 -0
  185. package/dist/src/sim/events.d.ts +25 -0
  186. package/dist/src/sim/events.js +5 -0
  187. package/dist/src/sim/explosion.d.ts +40 -0
  188. package/dist/src/sim/explosion.js +40 -0
  189. package/dist/src/sim/formation-unit.d.ts +138 -0
  190. package/dist/src/sim/formation-unit.js +197 -0
  191. package/dist/src/sim/formation.d.ts +12 -0
  192. package/dist/src/sim/formation.js +54 -0
  193. package/dist/src/sim/frontage.d.ts +30 -0
  194. package/dist/src/sim/frontage.js +84 -0
  195. package/dist/src/sim/grapple.d.ts +100 -0
  196. package/dist/src/sim/grapple.js +480 -0
  197. package/dist/src/sim/hazard.d.ts +104 -0
  198. package/dist/src/sim/hazard.js +201 -0
  199. package/dist/src/sim/hydrostatic.d.ts +58 -0
  200. package/dist/src/sim/hydrostatic.js +117 -0
  201. package/dist/src/sim/impairment.d.ts +20 -0
  202. package/dist/src/sim/impairment.js +162 -0
  203. package/dist/src/sim/indexing.d.ts +7 -0
  204. package/dist/src/sim/indexing.js +7 -0
  205. package/dist/src/sim/injury.d.ts +54 -0
  206. package/dist/src/sim/injury.js +66 -0
  207. package/dist/src/sim/intent.d.ts +26 -0
  208. package/dist/src/sim/intent.js +7 -0
  209. package/dist/src/sim/kernel.d.ts +45 -0
  210. package/dist/src/sim/kernel.js +1992 -0
  211. package/dist/src/sim/kinds.d.ts +64 -0
  212. package/dist/src/sim/kinds.js +56 -0
  213. package/dist/src/sim/knockback.d.ts +50 -0
  214. package/dist/src/sim/knockback.js +82 -0
  215. package/dist/src/sim/limb.d.ts +48 -0
  216. package/dist/src/sim/limb.js +78 -0
  217. package/dist/src/sim/medical.d.ts +32 -0
  218. package/dist/src/sim/medical.js +33 -0
  219. package/dist/src/sim/morale.d.ts +69 -0
  220. package/dist/src/sim/morale.js +92 -0
  221. package/dist/src/sim/mount.d.ts +150 -0
  222. package/dist/src/sim/mount.js +225 -0
  223. package/dist/src/sim/nutrition.d.ts +74 -0
  224. package/dist/src/sim/nutrition.js +168 -0
  225. package/dist/src/sim/occlusion.d.ts +8 -0
  226. package/dist/src/sim/occlusion.js +71 -0
  227. package/dist/src/sim/push.d.ts +11 -0
  228. package/dist/src/sim/push.js +79 -0
  229. package/dist/src/sim/ranged.d.ts +44 -0
  230. package/dist/src/sim/ranged.js +69 -0
  231. package/dist/src/sim/seeds.d.ts +3 -0
  232. package/dist/src/sim/seeds.js +16 -0
  233. package/dist/src/sim/sensory-extended.d.ts +103 -0
  234. package/dist/src/sim/sensory-extended.js +181 -0
  235. package/dist/src/sim/sensory.d.ts +38 -0
  236. package/dist/src/sim/sensory.js +109 -0
  237. package/dist/src/sim/skills.d.ts +70 -0
  238. package/dist/src/sim/skills.js +69 -0
  239. package/dist/src/sim/sleep.d.ts +107 -0
  240. package/dist/src/sim/sleep.js +215 -0
  241. package/dist/src/sim/spatial.d.ts +8 -0
  242. package/dist/src/sim/spatial.js +59 -0
  243. package/dist/src/sim/step/capability.d.ts +8 -0
  244. package/dist/src/sim/step/capability.js +77 -0
  245. package/dist/src/sim/step/concentration.d.ts +9 -0
  246. package/dist/src/sim/step/concentration.js +25 -0
  247. package/dist/src/sim/step/effects.d.ts +17 -0
  248. package/dist/src/sim/step/effects.js +96 -0
  249. package/dist/src/sim/step/energy.d.ts +3 -0
  250. package/dist/src/sim/step/energy.js +31 -0
  251. package/dist/src/sim/step/hazards.d.ts +4 -0
  252. package/dist/src/sim/step/hazards.js +19 -0
  253. package/dist/src/sim/step/injury.d.ts +10 -0
  254. package/dist/src/sim/step/injury.js +353 -0
  255. package/dist/src/sim/step/morale.d.ts +11 -0
  256. package/dist/src/sim/step/morale.js +130 -0
  257. package/dist/src/sim/step/movement.d.ts +5 -0
  258. package/dist/src/sim/step/movement.js +172 -0
  259. package/dist/src/sim/step/push.d.ts +11 -0
  260. package/dist/src/sim/step/push.js +79 -0
  261. package/dist/src/sim/step/substances.d.ts +3 -0
  262. package/dist/src/sim/step/substances.js +75 -0
  263. package/dist/src/sim/substance.d.ts +38 -0
  264. package/dist/src/sim/substance.js +57 -0
  265. package/dist/src/sim/systemic-toxicology.d.ts +109 -0
  266. package/dist/src/sim/systemic-toxicology.js +263 -0
  267. package/dist/src/sim/team.d.ts +9 -0
  268. package/dist/src/sim/team.js +37 -0
  269. package/dist/src/sim/tech.d.ts +36 -0
  270. package/dist/src/sim/tech.js +46 -0
  271. package/dist/src/sim/terrain.d.ts +121 -0
  272. package/dist/src/sim/terrain.js +141 -0
  273. package/dist/src/sim/testing.d.ts +13 -0
  274. package/dist/src/sim/testing.js +100 -0
  275. package/dist/src/sim/thermoregulation.d.ts +77 -0
  276. package/dist/src/sim/thermoregulation.js +161 -0
  277. package/dist/src/sim/tick.d.ts +3 -0
  278. package/dist/src/sim/tick.js +3 -0
  279. package/dist/src/sim/toxicology.d.ts +52 -0
  280. package/dist/src/sim/toxicology.js +104 -0
  281. package/dist/src/sim/trace.d.ts +141 -0
  282. package/dist/src/sim/trace.js +1 -0
  283. package/dist/src/sim/tuning.d.ts +16 -0
  284. package/dist/src/sim/tuning.js +42 -0
  285. package/dist/src/sim/vec3.d.ts +14 -0
  286. package/dist/src/sim/vec3.js +31 -0
  287. package/dist/src/sim/weapon_dynamics.d.ts +102 -0
  288. package/dist/src/sim/weapon_dynamics.js +142 -0
  289. package/dist/src/sim/weather.d.ts +95 -0
  290. package/dist/src/sim/weather.js +105 -0
  291. package/dist/src/sim/world.d.ts +52 -0
  292. package/dist/src/sim/world.js +1 -0
  293. package/dist/src/sim/wound-aging.d.ts +120 -0
  294. package/dist/src/sim/wound-aging.js +223 -0
  295. package/dist/src/species.d.ts +106 -0
  296. package/dist/src/species.js +664 -0
  297. package/dist/src/story-arcs.d.ts +17 -0
  298. package/dist/src/story-arcs.js +276 -0
  299. package/dist/src/tech-diffusion.d.ts +80 -0
  300. package/dist/src/tech-diffusion.js +185 -0
  301. package/dist/src/traits.d.ts +25 -0
  302. package/dist/src/traits.js +178 -0
  303. package/dist/src/types.d.ts +117 -0
  304. package/dist/src/types.js +1 -0
  305. package/dist/src/units.d.ts +41 -0
  306. package/dist/src/units.js +64 -0
  307. package/dist/src/weapons.d.ts +20 -0
  308. package/dist/src/weapons.js +824 -0
  309. package/dist/src/world-generation.d.ts +52 -0
  310. package/dist/src/world-generation.js +301 -0
  311. package/package.json +74 -0
@@ -0,0 +1,388 @@
1
+ const KNOWN_FUNCTION_IDS = new Set([
2
+ "mobility",
3
+ "manipulation",
4
+ "cns",
5
+ "vision",
6
+ "respiration",
7
+ "circulation",
8
+ "digestion",
9
+ "sensor",
10
+ "balance",
11
+ "weaponMount",
12
+ "vital",
13
+ ]);
14
+ export function validateExtendedBodyPlan(input) {
15
+ const issues = [];
16
+ if (!isRecord(input)) {
17
+ return fail([{ path: "$", message: "Expected an object body plan definition." }]);
18
+ }
19
+ const plan = input;
20
+ if (typeof plan.id !== "string" || plan.id.length === 0) {
21
+ issues.push({ path: "id", message: "Body plan id must be a non-empty string." });
22
+ }
23
+ if (!Array.isArray(plan.segments) || plan.segments.length === 0) {
24
+ issues.push({ path: "segments", message: "Body plan must define at least one segment." });
25
+ return fail(issues);
26
+ }
27
+ const segmentIds = new Set();
28
+ const parentsById = new Map();
29
+ for (let i = 0; i < plan.segments.length; i += 1) {
30
+ const seg = plan.segments[i];
31
+ const base = `segments[${i}]`;
32
+ if (!isRecord(seg)) {
33
+ issues.push({ path: base, message: "Segment must be an object." });
34
+ continue;
35
+ }
36
+ if (typeof seg.id !== "string" || seg.id.length === 0) {
37
+ issues.push({ path: `${base}.id`, message: "Segment id must be a non-empty string." });
38
+ continue;
39
+ }
40
+ if (segmentIds.has(seg.id)) {
41
+ issues.push({ path: `${base}.id`, message: `Duplicate segment id '${seg.id}'.` });
42
+ }
43
+ segmentIds.add(seg.id);
44
+ if (!(typeof seg.parent === "string" || seg.parent === null)) {
45
+ issues.push({ path: `${base}.parent`, message: "Segment parent must be a string id or null." });
46
+ }
47
+ else {
48
+ parentsById.set(seg.id, seg.parent);
49
+ }
50
+ if (typeof seg.mass_kg !== "number") {
51
+ issues.push({ path: `${base}.mass_kg`, message: "Segment mass_kg must be numeric." });
52
+ }
53
+ if (!isRecord(seg.exposureWeight)) {
54
+ issues.push({ path: `${base}.exposureWeight`, message: "Segment exposureWeight must be an object." });
55
+ }
56
+ }
57
+ for (const [segmentId, parentId] of parentsById) {
58
+ if (parentId !== null && !segmentIds.has(parentId)) {
59
+ issues.push({
60
+ path: `segments[${segmentId}].parent`,
61
+ message: `Segment '${segmentId}' points to unknown parent '${parentId}'.`,
62
+ });
63
+ }
64
+ }
65
+ detectCycles(parentsById, issues);
66
+ validateSegmentData(plan, segmentIds, issues);
67
+ validateProfiles(plan, segmentIds, issues);
68
+ validateContracts(plan, segmentIds, issues);
69
+ return issues.length === 0 ? ok(plan) : fail(issues);
70
+ }
71
+ function validateSegmentData(plan, segmentIds, issues) {
72
+ const data = plan.segmentData;
73
+ if (!data)
74
+ return;
75
+ if (!isRecord(data)) {
76
+ issues.push({ path: "segmentData", message: "segmentData must be an object keyed by segment id." });
77
+ return;
78
+ }
79
+ for (const [segmentId, def] of Object.entries(data)) {
80
+ if (!segmentIds.has(segmentId)) {
81
+ issues.push({
82
+ path: `segmentData.${segmentId}`,
83
+ message: `segmentData references unknown segment '${segmentId}'.`,
84
+ });
85
+ continue;
86
+ }
87
+ if (!isRecord(def)) {
88
+ issues.push({ path: `segmentData.${segmentId}`, message: "segmentData entry must be an object." });
89
+ continue;
90
+ }
91
+ if (def.tags !== undefined && !isStringArray(def.tags)) {
92
+ issues.push({ path: `segmentData.${segmentId}.tags`, message: "tags must be a string array." });
93
+ }
94
+ if (def.tissues !== undefined)
95
+ validateTissues(segmentId, def.tissues, issues);
96
+ if (def.organs !== undefined)
97
+ validateOrgans(segmentId, def.organs, issues);
98
+ if (def.functions !== undefined)
99
+ validateFunctions(segmentId, def.functions, issues);
100
+ }
101
+ }
102
+ function validateTissues(segmentId, tissues, issues) {
103
+ if (!Array.isArray(tissues)) {
104
+ issues.push({ path: `segmentData.${segmentId}.tissues`, message: "tissues must be an array." });
105
+ return;
106
+ }
107
+ const ids = new Set();
108
+ tissues.forEach((t, idx) => {
109
+ const base = `segmentData.${segmentId}.tissues[${idx}]`;
110
+ if (!isRecord(t)) {
111
+ issues.push({ path: base, message: "Tissue definition must be an object." });
112
+ return;
113
+ }
114
+ if (typeof t.id !== "string" || t.id.length === 0) {
115
+ issues.push({ path: `${base}.id`, message: "Tissue id must be a non-empty string." });
116
+ }
117
+ else if (ids.has(t.id)) {
118
+ issues.push({ path: `${base}.id`, message: `Duplicate tissue id '${t.id}'.` });
119
+ }
120
+ else {
121
+ ids.add(t.id);
122
+ }
123
+ if (typeof t.kind !== "string" || t.kind.length === 0) {
124
+ issues.push({ path: `${base}.kind`, message: "Tissue kind must be a non-empty string." });
125
+ }
126
+ if (t.integrity !== undefined && typeof t.integrity !== "number") {
127
+ issues.push({ path: `${base}.integrity`, message: "Tissue integrity must be numeric when present." });
128
+ }
129
+ if (t.tags !== undefined && !isStringArray(t.tags)) {
130
+ issues.push({ path: `${base}.tags`, message: "Tissue tags must be a string array." });
131
+ }
132
+ });
133
+ }
134
+ function validateOrgans(segmentId, organs, issues) {
135
+ if (!Array.isArray(organs)) {
136
+ issues.push({ path: `segmentData.${segmentId}.organs`, message: "organs must be an array." });
137
+ return;
138
+ }
139
+ const ids = new Set();
140
+ organs.forEach((o, idx) => {
141
+ const base = `segmentData.${segmentId}.organs[${idx}]`;
142
+ if (!isRecord(o)) {
143
+ issues.push({ path: base, message: "Organ definition must be an object." });
144
+ return;
145
+ }
146
+ if (typeof o.id !== "string" || o.id.length === 0) {
147
+ issues.push({ path: `${base}.id`, message: "Organ id must be a non-empty string." });
148
+ }
149
+ else if (ids.has(o.id)) {
150
+ issues.push({ path: `${base}.id`, message: `Duplicate organ id '${o.id}'.` });
151
+ }
152
+ else {
153
+ ids.add(o.id);
154
+ }
155
+ if (typeof o.kind !== "string" || o.kind.length === 0) {
156
+ issues.push({ path: `${base}.kind`, message: "Organ kind must be a non-empty string." });
157
+ }
158
+ if (o.functionIds !== undefined && !isStringArray(o.functionIds)) {
159
+ issues.push({ path: `${base}.functionIds`, message: "Organ functionIds must be a string array." });
160
+ }
161
+ if (o.tags !== undefined && !isStringArray(o.tags)) {
162
+ issues.push({ path: `${base}.tags`, message: "Organ tags must be a string array." });
163
+ }
164
+ if (o.vital !== undefined && typeof o.vital !== "boolean") {
165
+ issues.push({ path: `${base}.vital`, message: "Organ vital must be boolean when present." });
166
+ }
167
+ });
168
+ }
169
+ function validateFunctions(segmentId, fns, issues) {
170
+ if (!Array.isArray(fns)) {
171
+ issues.push({ path: `segmentData.${segmentId}.functions`, message: "functions must be an array." });
172
+ return;
173
+ }
174
+ fns.forEach((fn, idx) => {
175
+ const base = `segmentData.${segmentId}.functions[${idx}]`;
176
+ if (!isRecord(fn)) {
177
+ issues.push({ path: base, message: "Function definition must be an object." });
178
+ return;
179
+ }
180
+ if (typeof fn.id !== "string" || fn.id.length === 0) {
181
+ issues.push({ path: `${base}.id`, message: "Function id must be a non-empty string." });
182
+ }
183
+ if (fn.role !== undefined && !["primary", "secondary", "support", "none"].includes(String(fn.role))) {
184
+ issues.push({ path: `${base}.role`, message: "Function role must be primary/secondary/support/none." });
185
+ }
186
+ if (fn.weight !== undefined && typeof fn.weight !== "number") {
187
+ issues.push({ path: `${base}.weight`, message: "Function weight must be numeric when present." });
188
+ }
189
+ if (fn.tags !== undefined && !isStringArray(fn.tags)) {
190
+ issues.push({ path: `${base}.tags`, message: "Function tags must be a string array." });
191
+ }
192
+ if (typeof fn.id === "string" && !KNOWN_FUNCTION_IDS.has(fn.id) && !fn.id.startsWith("x:")) {
193
+ issues.push({
194
+ path: `${base}.id`,
195
+ message: `Unknown function id '${fn.id}'. Use a known id or namespace custom ids with 'x:'.`,
196
+ });
197
+ }
198
+ });
199
+ }
200
+ function validateProfiles(plan, segmentIds, issues) {
201
+ if (plan.targetProfiles !== undefined) {
202
+ if (!Array.isArray(plan.targetProfiles)) {
203
+ issues.push({ path: "targetProfiles", message: "targetProfiles must be an array." });
204
+ }
205
+ else {
206
+ const ids = new Set();
207
+ plan.targetProfiles.forEach((profile, idx) => {
208
+ const base = `targetProfiles[${idx}]`;
209
+ if (!validateProfileId(base, profile?.id, ids, issues))
210
+ return;
211
+ if (!Array.isArray(profile.selectors) || profile.selectors.length === 0) {
212
+ issues.push({ path: `${base}.selectors`, message: "Target profile must define selectors." });
213
+ }
214
+ else {
215
+ profile.selectors.forEach((selector, sIdx) => {
216
+ validateSelector(`${base}.selectors[${sIdx}]`, selector, segmentIds, issues);
217
+ if (typeof selector.weight !== "number" || selector.weight <= 0) {
218
+ issues.push({
219
+ path: `${base}.selectors[${sIdx}].weight`,
220
+ message: "Weighted selector weight must be a positive number.",
221
+ });
222
+ }
223
+ });
224
+ }
225
+ });
226
+ }
227
+ }
228
+ if (plan.coverageProfiles !== undefined) {
229
+ if (!Array.isArray(plan.coverageProfiles)) {
230
+ issues.push({ path: "coverageProfiles", message: "coverageProfiles must be an array." });
231
+ }
232
+ else {
233
+ const ids = new Set();
234
+ plan.coverageProfiles.forEach((profile, idx) => {
235
+ const base = `coverageProfiles[${idx}]`;
236
+ if (!validateProfileId(base, profile?.id, ids, issues))
237
+ return;
238
+ if (profile.tags !== undefined && !isStringArray(profile.tags)) {
239
+ issues.push({ path: `${base}.tags`, message: "Coverage profile tags must be a string array." });
240
+ }
241
+ if (!Array.isArray(profile.selectors) || profile.selectors.length === 0) {
242
+ issues.push({ path: `${base}.selectors`, message: "Coverage profile must define selectors." });
243
+ }
244
+ else {
245
+ profile.selectors.forEach((selector, sIdx) => {
246
+ validateSelector(`${base}.selectors[${sIdx}]`, selector, segmentIds, issues);
247
+ });
248
+ }
249
+ });
250
+ }
251
+ }
252
+ }
253
+ function validateContracts(plan, segmentIds, issues) {
254
+ const humanoid = plan.contracts?.humanoidTargeting;
255
+ if (!humanoid)
256
+ return;
257
+ const paths = [
258
+ ["head", humanoid.head],
259
+ ["torso", humanoid.torso],
260
+ ["leftArm", humanoid.leftArm],
261
+ ["rightArm", humanoid.rightArm],
262
+ ["leftLeg", humanoid.leftLeg],
263
+ ["rightLeg", humanoid.rightLeg],
264
+ ];
265
+ for (const [key, ids] of paths) {
266
+ if (ids === undefined)
267
+ continue;
268
+ if (!isStringArray(ids)) {
269
+ issues.push({
270
+ path: `contracts.humanoidTargeting.${String(key)}`,
271
+ message: "Humanoid alias entry must be a string array.",
272
+ });
273
+ continue;
274
+ }
275
+ for (const id of ids) {
276
+ if (!segmentIds.has(id)) {
277
+ issues.push({
278
+ path: `contracts.humanoidTargeting.${String(key)}`,
279
+ message: `Unknown segment '${id}' in humanoid target alias '${String(key)}'.`,
280
+ });
281
+ }
282
+ }
283
+ }
284
+ }
285
+ function validateSelector(path, selector, segmentIds, issues) {
286
+ if (!isRecord(selector)) {
287
+ issues.push({ path, message: "Selector must be an object." });
288
+ return;
289
+ }
290
+ const hasAnyCriterion = selector.ids !== undefined ||
291
+ selector.tags !== undefined ||
292
+ selector.functionIds !== undefined ||
293
+ selector.subtreeOf !== undefined ||
294
+ selector.anyOf !== undefined ||
295
+ selector.allOf !== undefined;
296
+ if (!hasAnyCriterion) {
297
+ issues.push({ path, message: "Selector must define at least one criterion." });
298
+ }
299
+ if (selector.ids !== undefined) {
300
+ if (!isStringArray(selector.ids)) {
301
+ issues.push({ path: `${path}.ids`, message: "ids must be a string array." });
302
+ }
303
+ else {
304
+ for (const id of selector.ids) {
305
+ if (!segmentIds.has(id)) {
306
+ issues.push({ path: `${path}.ids`, message: `Unknown segment '${id}' in selector.` });
307
+ }
308
+ }
309
+ }
310
+ }
311
+ if (selector.tags !== undefined && !isStringArray(selector.tags)) {
312
+ issues.push({ path: `${path}.tags`, message: "tags must be a string array." });
313
+ }
314
+ if (selector.functionIds !== undefined && !isStringArray(selector.functionIds)) {
315
+ issues.push({ path: `${path}.functionIds`, message: "functionIds must be a string array." });
316
+ }
317
+ if (selector.subtreeOf !== undefined) {
318
+ if (typeof selector.subtreeOf !== "string") {
319
+ issues.push({ path: `${path}.subtreeOf`, message: "subtreeOf must be a segment id string." });
320
+ }
321
+ else if (!segmentIds.has(selector.subtreeOf)) {
322
+ issues.push({ path: `${path}.subtreeOf`, message: `Unknown subtree root '${selector.subtreeOf}'.` });
323
+ }
324
+ }
325
+ if (selector.anyOf !== undefined) {
326
+ if (!Array.isArray(selector.anyOf) || selector.anyOf.length === 0) {
327
+ issues.push({ path: `${path}.anyOf`, message: "anyOf must be a non-empty selector array." });
328
+ }
329
+ else {
330
+ selector.anyOf.forEach((nested, idx) => validateSelector(`${path}.anyOf[${idx}]`, nested, segmentIds, issues));
331
+ }
332
+ }
333
+ if (selector.allOf !== undefined) {
334
+ if (!Array.isArray(selector.allOf) || selector.allOf.length === 0) {
335
+ issues.push({ path: `${path}.allOf`, message: "allOf must be a non-empty selector array." });
336
+ }
337
+ else {
338
+ selector.allOf.forEach((nested, idx) => validateSelector(`${path}.allOf[${idx}]`, nested, segmentIds, issues));
339
+ }
340
+ }
341
+ if (selector.exclude !== undefined) {
342
+ validateSelector(`${path}.exclude`, selector.exclude, segmentIds, issues);
343
+ }
344
+ }
345
+ function validateProfileId(path, id, ids, issues) {
346
+ if (typeof id !== "string" || id.length === 0) {
347
+ issues.push({ path: `${path}.id`, message: "Profile id must be a non-empty string." });
348
+ return false;
349
+ }
350
+ if (ids.has(id)) {
351
+ issues.push({ path: `${path}.id`, message: `Duplicate profile id '${id}'.` });
352
+ return false;
353
+ }
354
+ ids.add(id);
355
+ return true;
356
+ }
357
+ function detectCycles(parentsById, issues) {
358
+ const seen = new Set();
359
+ const visiting = new Set();
360
+ const walk = (id) => {
361
+ if (seen.has(id))
362
+ return;
363
+ if (visiting.has(id)) {
364
+ issues.push({ path: `segments[${id}]`, message: `Cycle detected at segment '${id}'.` });
365
+ return;
366
+ }
367
+ visiting.add(id);
368
+ const parent = parentsById.get(id);
369
+ if (parent)
370
+ walk(parent);
371
+ visiting.delete(id);
372
+ seen.add(id);
373
+ };
374
+ for (const id of parentsById.keys())
375
+ walk(id);
376
+ }
377
+ function isRecord(value) {
378
+ return typeof value === "object" && value !== null && !Array.isArray(value);
379
+ }
380
+ function isStringArray(value) {
381
+ return Array.isArray(value) && value.every(v => typeof v === "string");
382
+ }
383
+ function ok(value) {
384
+ return { ok: true, value, issues: [] };
385
+ }
386
+ function fail(issues) {
387
+ return { ok: false, issues };
388
+ }
@@ -0,0 +1,4 @@
1
+ export * from "./anatomy-contracts.js";
2
+ export * from "./anatomy-schema.js";
3
+ export * from "./anatomy-helpers.js";
4
+ export * from "./anatomy-compiler.js";
@@ -0,0 +1,4 @@
1
+ export * from "./anatomy-contracts.js";
2
+ export * from "./anatomy-schema.js";
3
+ export * from "./anatomy-helpers.js";
4
+ export * from "./anatomy-compiler.js";
@@ -0,0 +1,87 @@
1
+ import { type Q, type I32 } from "./units.js";
2
+ import type { CognitiveProfile } from "./types.js";
3
+ export interface Archetype {
4
+ stature_m: I32;
5
+ mass_kg: I32;
6
+ visionRange_m: I32;
7
+ visionArcDeg: number;
8
+ hearingRange_m: I32;
9
+ decisionLatency_s: I32;
10
+ attentionDepth: number;
11
+ threatHorizon_m: I32;
12
+ statureVar: Q;
13
+ massVar: Q;
14
+ reachVar: Q;
15
+ actuatorScaleVar: Q;
16
+ structureScaleVar: Q;
17
+ actuatorMassFrac: Q;
18
+ actuatorMassVar: Q;
19
+ peakForce_N: I32;
20
+ peakForceVar: Q;
21
+ peakPower_W: I32;
22
+ peakPowerVar: Q;
23
+ continuousPower_W: I32;
24
+ continuousPowerVar: Q;
25
+ reserveEnergy_J: I32;
26
+ reserveEnergyVar: Q;
27
+ conversionEfficiency: Q;
28
+ efficiencyVar: Q;
29
+ reactionTime_s: I32;
30
+ reactionTimeVar: Q;
31
+ controlQuality: Q;
32
+ controlVar: Q;
33
+ stability: Q;
34
+ stabilityVar: Q;
35
+ fineControl: Q;
36
+ fineControlVar: Q;
37
+ surfaceIntegrity: Q;
38
+ surfaceVar: Q;
39
+ bulkIntegrity: Q;
40
+ bulkVar: Q;
41
+ structureIntegrity: Q;
42
+ structVar: Q;
43
+ distressTolerance: Q;
44
+ distressVar: Q;
45
+ shockTolerance: Q;
46
+ shockVar: Q;
47
+ concussionTolerance: Q;
48
+ concVar: Q;
49
+ heatTolerance: Q;
50
+ heatVar: Q;
51
+ coldTolerance: Q;
52
+ coldVar: Q;
53
+ fatigueRate: Q;
54
+ fatigueVar: Q;
55
+ recoveryRate: Q;
56
+ recoveryVar: Q;
57
+ /** Phase 33: species-typical cognitive profile (no per-individual variance). */
58
+ cognition?: CognitiveProfile;
59
+ }
60
+ export declare const HUMAN_BASE: Archetype;
61
+ /**
62
+ * Amateur boxer — British Journal of Sports Medicine, Walilko et al.
63
+ * Amateur punch force: 2,500–4,000 N (nominal 2,800 N used).
64
+ */
65
+ export declare const AMATEUR_BOXER: Archetype;
66
+ /**
67
+ * Pro boxer — biomechanics studies on elite boxers.
68
+ * Elite punch force: 4,000–7,000 N (nominal 5,000 N, cruiserweight/light-heavy).
69
+ */
70
+ export declare const PRO_BOXER: Archetype;
71
+ /**
72
+ * Greco-Roman wrestler — Olympic grappling literature.
73
+ * Grip ~500 N forearm; whole-body throw ~2,000 N.
74
+ */
75
+ export declare const GRECO_WRESTLER: Archetype;
76
+ /**
77
+ * Medieval knight infantry — trained warrior; armour applied via preset loadout.
78
+ */
79
+ export declare const KNIGHT_INFANTRY: Archetype;
80
+ /**
81
+ * Large Pacific Octopus (Enteroctopus dofleini).
82
+ * Arm muscle force ~150 N × 8 arms ≈ 1,200 N total burst.
83
+ * ~2,000 suckers → extremely high controlQuality + grappling skill in presets.
84
+ * Distributed nervous system → high concussionTolerance, low structureIntegrity (no skeleton).
85
+ */
86
+ export declare const LARGE_PACIFIC_OCTOPUS: Archetype;
87
+ export declare const SERVICE_ROBOT: Archetype;