@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,694 @@
1
+ // src/competence/framework.ts — Phase 40: Non-Combat Competence Framework
2
+ //
3
+ // Unified competence resolution system that:
4
+ // 1. Routes to correct domain-specific resolver
5
+ // 2. Integrates with Phase 21 progression (XP gain)
6
+ // 3. Provides canonical CompetenceAction/CompetenceOutcome types
7
+ //
8
+ // No kernel import — pure resolution module.
9
+ import { SCALE, q, clampQ, mulDiv } from "../units.js";
10
+ import { makeRng } from "../rng.js";
11
+ import { getTaskById } from "./catalogue.js";
12
+ // Import domain-specific resolvers
13
+ import { resolveCrafting } from "./crafting.js";
14
+ import { resolveNavigation } from "./navigation.js";
15
+ import { resolveTracking, resolveForaging, resolveTaming, } from "./naturalist.js";
16
+ import { resolveSignal } from "./interspecies.js";
17
+ import { resolveTeaching } from "./teaching.js";
18
+ import { resolveEngineering } from "./engineering.js";
19
+ import { resolveFormationSignal } from "./acoustic.js";
20
+ import { resolvePerformance } from "./performance.js";
21
+ // ── Constants ─────────────────────────────────────────────────────────────────
22
+ /** Base XP for successful task completion. */
23
+ const BASE_XP_SUCCESS = 10;
24
+ /** XP multiplier for outcome quality. */
25
+ const QUALITY_XP_MULTIPLIERS = {
26
+ exceptional: 2.0,
27
+ good: 1.5,
28
+ adequate: 1.0,
29
+ poor: 0.5,
30
+ failure: 0,
31
+ };
32
+ /** Difficulty XP bonus: harder tasks grant more XP. */
33
+ const MAX_DIFFICULTY_BONUS = 15;
34
+ /** Tool quality bonus lookup (default if tool not specified). */
35
+ const DEFAULT_TOOL_BONUS = q(1.0);
36
+ // ── Helper Functions ──────────────────────────────────────────────────────────
37
+ /**
38
+ * Map domain-specific descriptors to canonical descriptors.
39
+ */
40
+ function canonicalizeDescriptor(descriptor) {
41
+ switch (descriptor) {
42
+ case "exceptional":
43
+ case "masterwork":
44
+ return "exceptional";
45
+ case "good":
46
+ case "fine":
47
+ return "good";
48
+ case "adequate":
49
+ return "adequate";
50
+ case "poor":
51
+ return "poor";
52
+ case "failure":
53
+ case "ruined":
54
+ return "failure";
55
+ default:
56
+ return "adequate";
57
+ }
58
+ }
59
+ /**
60
+ * Calculate XP gain based on outcome.
61
+ */
62
+ function calculateXP(descriptor, difficulty_Q) {
63
+ const qualityMul = QUALITY_XP_MULTIPLIERS[descriptor];
64
+ // No XP for failure, no difficulty bonus on failure
65
+ if (descriptor === "failure") {
66
+ return 0;
67
+ }
68
+ const difficultyBonus = Math.round((difficulty_Q / SCALE.Q) * MAX_DIFFICULTY_BONUS);
69
+ return Math.round(BASE_XP_SUCCESS * qualityMul) + difficultyBonus;
70
+ }
71
+ /**
72
+ * Generate narrative line for outcome.
73
+ */
74
+ function generateNarrative(task, outcome, actor) {
75
+ const actorName = `Entity ${actor.id}`;
76
+ const taskName = task.description.toLowerCase();
77
+ switch (outcome.descriptor) {
78
+ case "exceptional":
79
+ return `${actorName} achieved an exceptional result ${taskName}, surpassing all expectations.`;
80
+ case "good":
81
+ return `${actorName} successfully completed ${taskName} with good quality.`;
82
+ case "adequate":
83
+ return `${actorName} managed ${taskName} adequately, meeting basic requirements.`;
84
+ case "poor":
85
+ return `${actorName} struggled with ${taskName}, producing a poor result.`;
86
+ case "failure":
87
+ return `${actorName} failed to complete ${taskName}.`;
88
+ default:
89
+ return `${actorName} attempted ${taskName}.`;
90
+ }
91
+ }
92
+ /**
93
+ * Get the relevant cognitive attribute for a domain.
94
+ */
95
+ function getDomainIntelligence(entity, domain) {
96
+ const cognition = entity.attributes.cognition;
97
+ if (!cognition)
98
+ return q(0.50);
99
+ switch (domain) {
100
+ case "linguistic":
101
+ return (cognition.linguistic ?? q(0.50));
102
+ case "logicalMathematical":
103
+ return (cognition.logicalMathematical ?? q(0.50));
104
+ case "spatial":
105
+ return (cognition.spatial ?? q(0.50));
106
+ case "bodilyKinesthetic":
107
+ return (cognition.bodilyKinesthetic ?? q(0.50));
108
+ case "musical":
109
+ return (cognition.musical ?? q(0.50));
110
+ case "interpersonal":
111
+ return (cognition.interpersonal ?? q(0.50));
112
+ case "intrapersonal":
113
+ return (cognition.intrapersonal ?? q(0.50));
114
+ case "naturalist":
115
+ return (cognition.naturalist ?? q(0.50));
116
+ case "interSpecies":
117
+ return (cognition.interSpecies ?? q(0.35));
118
+ default:
119
+ return q(0.50);
120
+ }
121
+ }
122
+ // ── Domain Routers ────────────────────────────────────────────────────────────
123
+ /**
124
+ * Resolve bodily-kinesthetic tasks (crafting, physical skill).
125
+ */
126
+ function resolveBodilyKinesthetic(actor, task, action) {
127
+ const seed = action.seed;
128
+ // Map task to crafting spec
129
+ const toolCategory = task.taskId.includes("sword")
130
+ ? "forge"
131
+ : task.taskId.includes("surgery")
132
+ ? "precision"
133
+ : undefined;
134
+ const spec = {
135
+ outputId: task.taskId,
136
+ materialQ: q(0.50),
137
+ baseTime_s: task.timeBase_s,
138
+ minBKQ: q(0.20),
139
+ ...(toolCategory !== undefined && { toolCategory }),
140
+ };
141
+ const result = resolveCrafting(actor, spec, seed);
142
+ return {
143
+ quality_Q: result.quality_Q,
144
+ timeTaken_s: result.timeTaken_s,
145
+ success: result.descriptor !== "ruined",
146
+ descriptor: canonicalizeDescriptor(result.descriptor),
147
+ details: {
148
+ qualityMul: result.quality_Q,
149
+ latentFlaw: result.descriptor === "poor",
150
+ },
151
+ };
152
+ }
153
+ /**
154
+ * Resolve spatial tasks (navigation, wayfinding).
155
+ */
156
+ function resolveSpatial(actor, task, action) {
157
+ const terrain = action.terrain ?? "forest";
158
+ const hasMap = action.toolId === "map";
159
+ const spec = {
160
+ terrain: terrain,
161
+ visibility: "clear",
162
+ distance_m: 1000,
163
+ hasMap,
164
+ };
165
+ const result = resolveNavigation(actor, spec, action.seed);
166
+ // Determine descriptor based on efficiency
167
+ let descriptor;
168
+ if (result.routeEfficiency >= q(0.90))
169
+ descriptor = "exceptional";
170
+ else if (result.routeEfficiency >= q(0.75))
171
+ descriptor = "good";
172
+ else if (result.routeEfficiency >= q(0.50))
173
+ descriptor = "adequate";
174
+ else if (result.routeEfficiency >= q(0.30))
175
+ descriptor = "poor";
176
+ else
177
+ descriptor = "failure";
178
+ return {
179
+ quality_Q: result.routeEfficiency,
180
+ timeTaken_s: task.timeBase_s + result.timeLost_s,
181
+ success: result.routeEfficiency >= q(0.30),
182
+ descriptor,
183
+ details: { efficiency_Q: result.routeEfficiency },
184
+ };
185
+ }
186
+ /**
187
+ * Resolve naturalist tasks (tracking, foraging, taming).
188
+ */
189
+ function resolveNaturalist(actor, task, action) {
190
+ const seed = action.seed;
191
+ if (task.taskId.includes("track")) {
192
+ const spec = {
193
+ trackAge_s: task.taskId.includes("fresh") ? 1800 : 86400,
194
+ terrain: "forest",
195
+ quarrySpecies: "human",
196
+ };
197
+ const result = resolveTracking(actor, spec, seed);
198
+ let descriptor;
199
+ if (result.confidence_Q >= q(0.80))
200
+ descriptor = "exceptional";
201
+ else if (result.confidence_Q >= q(0.60))
202
+ descriptor = "good";
203
+ else if (result.confidence_Q >= q(0.40))
204
+ descriptor = "adequate";
205
+ else if (result.confidence_Q >= q(0.20))
206
+ descriptor = "poor";
207
+ else
208
+ descriptor = "failure";
209
+ return {
210
+ quality_Q: result.confidence_Q,
211
+ timeTaken_s: task.timeBase_s,
212
+ success: result.confidence_Q >= q(0.40),
213
+ descriptor,
214
+ details: { confidence_Q: result.confidence_Q, trackRange_m: result.trackRange_m },
215
+ };
216
+ }
217
+ if (task.taskId.includes("forage") || task.taskId.includes("identify")) {
218
+ const spec = {
219
+ searchHours: task.timeBase_s / 3600,
220
+ biome: "forest",
221
+ season: "summer",
222
+ };
223
+ const result = resolveForaging(actor, spec, seed);
224
+ let descriptor;
225
+ if (result.misidentified)
226
+ descriptor = "failure";
227
+ else if (result.herbQuality_Q >= q(0.80))
228
+ descriptor = "exceptional";
229
+ else if (result.herbQuality_Q >= q(0.60))
230
+ descriptor = "good";
231
+ else if (result.itemsFound >= 2)
232
+ descriptor = "adequate";
233
+ else
234
+ descriptor = "poor";
235
+ return {
236
+ quality_Q: result.herbQuality_Q,
237
+ timeTaken_s: task.timeBase_s,
238
+ success: !result.misidentified && result.itemsFound > 0,
239
+ descriptor,
240
+ details: { itemsFound: result.itemsFound, herbQuality_Q: result.herbQuality_Q },
241
+ };
242
+ }
243
+ if (task.taskId.includes("tame")) {
244
+ const spec = {
245
+ animalSpecies: "horse",
246
+ animalFearQ: q(0.40),
247
+ effortFactor: q(1.0),
248
+ priorSuccesses: 0,
249
+ };
250
+ const result = resolveTaming(actor, spec, seed);
251
+ let descriptor;
252
+ if (result.attacked)
253
+ descriptor = "failure";
254
+ else if (result.trust_Q >= q(0.90))
255
+ descriptor = "exceptional";
256
+ else if (result.trust_Q >= q(0.60))
257
+ descriptor = "good";
258
+ else if (result.trust_Q >= q(0.30))
259
+ descriptor = "adequate";
260
+ else
261
+ descriptor = "poor";
262
+ return {
263
+ quality_Q: result.trust_Q,
264
+ timeTaken_s: task.timeBase_s,
265
+ success: !result.attacked && result.trust_Q >= q(0.30),
266
+ descriptor,
267
+ details: { trust_Q: result.trust_Q, attacked: result.attacked },
268
+ };
269
+ }
270
+ // Default fallback
271
+ return {
272
+ quality_Q: q(0.50),
273
+ timeTaken_s: task.timeBase_s,
274
+ success: true,
275
+ descriptor: "adequate",
276
+ details: {},
277
+ };
278
+ }
279
+ /**
280
+ * Resolve inter-species tasks.
281
+ */
282
+ function resolveInterSpecies(actor, task, action, world) {
283
+ const seed = action.seed;
284
+ const spec = {
285
+ targetSpecies: "unknown",
286
+ intent: task.taskId.includes("calm") ? "calm" : "ally",
287
+ targetFearQ: q(0.50),
288
+ };
289
+ const result = resolveSignal(actor, spec, seed);
290
+ let descriptor;
291
+ if (result.aggravated)
292
+ descriptor = "failure";
293
+ else if (result.comprehension_Q >= q(0.80))
294
+ descriptor = "exceptional";
295
+ else if (result.comprehension_Q >= q(0.60))
296
+ descriptor = "good";
297
+ else if (result.comprehension_Q >= q(0.40))
298
+ descriptor = "adequate";
299
+ else
300
+ descriptor = "poor";
301
+ return {
302
+ quality_Q: result.comprehension_Q,
303
+ timeTaken_s: task.timeBase_s,
304
+ success: result.comprehension_Q >= q(0.40) && !result.aggravated,
305
+ descriptor,
306
+ details: { comprehension_Q: result.comprehension_Q, aggravated: result.aggravated },
307
+ };
308
+ }
309
+ /**
310
+ * Resolve linguistic tasks.
311
+ */
312
+ function resolveLinguistic(actor, task, action, world) {
313
+ if (task.taskId.includes("command")) {
314
+ // Use formation signal for command tasks
315
+ const formationSignal = task.taskId.includes("formation")
316
+ ? "advance"
317
+ : "hold";
318
+ // Need a listener - use self as placeholder or find in world
319
+ const listener = action.targetEntityId
320
+ ? world.entities.find((e) => e.id === action.targetEntityId) ?? actor
321
+ : actor;
322
+ const result = resolveFormationSignal(actor, formationSignal, listener, 10);
323
+ let descriptor;
324
+ if (result.received && result.clarity_Q >= q(0.80))
325
+ descriptor = "exceptional";
326
+ else if (result.received && result.clarity_Q >= q(0.60))
327
+ descriptor = "good";
328
+ else if (result.received)
329
+ descriptor = "adequate";
330
+ else if (result.clarity_Q >= q(0.30))
331
+ descriptor = "poor";
332
+ else
333
+ descriptor = "failure";
334
+ return {
335
+ quality_Q: result.clarity_Q,
336
+ timeTaken_s: result.latency_ms,
337
+ success: result.received,
338
+ descriptor,
339
+ details: { clarity_Q: result.clarity_Q, latency_ms: result.latency_ms },
340
+ };
341
+ }
342
+ if (task.taskId.includes("negotiate")) {
343
+ // Negotiation uses interpersonal + linguistic
344
+ const intPersonal = getDomainIntelligence(actor, "interpersonal");
345
+ const intLinguistic = getDomainIntelligence(actor, "linguistic");
346
+ const combined = mulDiv(intPersonal, intLinguistic, SCALE.Q);
347
+ // Apply difficulty
348
+ const difficultyPenalty = mulDiv(task.difficulty_Q, q(0.30), SCALE.Q);
349
+ const effectiveSkill = clampQ((combined - difficultyPenalty), q(0), SCALE.Q);
350
+ const rng = makeRng(action.seed, SCALE.Q);
351
+ const roll = rng.q01();
352
+ const success = roll < effectiveSkill;
353
+ let descriptor;
354
+ if (effectiveSkill >= q(0.85) && success)
355
+ descriptor = "exceptional";
356
+ else if (effectiveSkill >= q(0.65) && success)
357
+ descriptor = "good";
358
+ else if (success)
359
+ descriptor = "adequate";
360
+ else if (effectiveSkill >= q(0.40))
361
+ descriptor = "poor";
362
+ else
363
+ descriptor = "failure";
364
+ return {
365
+ quality_Q: effectiveSkill,
366
+ timeTaken_s: task.timeBase_s,
367
+ success,
368
+ descriptor,
369
+ details: { effectiveSkill_Q: effectiveSkill },
370
+ };
371
+ }
372
+ // Default translation/command task - simplified
373
+ const linguistic = getDomainIntelligence(actor, "linguistic");
374
+ let descriptor;
375
+ if (linguistic >= q(0.80))
376
+ descriptor = "exceptional";
377
+ else if (linguistic >= q(0.65))
378
+ descriptor = "good";
379
+ else if (linguistic >= q(0.50))
380
+ descriptor = "adequate";
381
+ else if (linguistic >= q(0.30))
382
+ descriptor = "poor";
383
+ else
384
+ descriptor = "failure";
385
+ return {
386
+ quality_Q: linguistic,
387
+ timeTaken_s: task.timeBase_s,
388
+ success: linguistic >= q(0.50),
389
+ descriptor,
390
+ details: { linguistic_Q: linguistic },
391
+ };
392
+ }
393
+ /**
394
+ * Resolve interpersonal tasks.
395
+ */
396
+ function resolveInterpersonal(actor, task, action, world) {
397
+ if (task.taskId.includes("teach")) {
398
+ // Find learner
399
+ const learner = action.targetEntityId
400
+ ? world.entities.find((e) => e.id === action.targetEntityId)
401
+ : undefined;
402
+ if (!learner) {
403
+ return {
404
+ quality_Q: q(0),
405
+ timeTaken_s: task.timeBase_s,
406
+ success: false,
407
+ descriptor: "failure",
408
+ details: { error: "No learner found" },
409
+ };
410
+ }
411
+ const spec = {
412
+ domain: "meleeCombat",
413
+ hours: task.timeBase_s / 3600,
414
+ };
415
+ const result = resolveTeaching(actor, learner, spec);
416
+ let descriptor;
417
+ if (result.xpGained >= 30)
418
+ descriptor = "exceptional";
419
+ else if (result.xpGained >= 20)
420
+ descriptor = "good";
421
+ else if (result.xpGained >= 10)
422
+ descriptor = "adequate";
423
+ else if (result.xpGained > 0)
424
+ descriptor = "poor";
425
+ else
426
+ descriptor = "failure";
427
+ return {
428
+ quality_Q: result.teachingQuality_Q,
429
+ timeTaken_s: task.timeBase_s,
430
+ success: result.xpGained > 0,
431
+ descriptor,
432
+ details: { xpGained: result.xpGained, teacherFatigueJ: result.teacherFatigueJ },
433
+ };
434
+ }
435
+ if (task.taskId.includes("rally")) {
436
+ // Rally uses interpersonal + willpower check
437
+ const interpersonal = getDomainIntelligence(actor, "interpersonal");
438
+ const rng = makeRng(action.seed, SCALE.Q);
439
+ const roll = rng.q01();
440
+ const success = roll < interpersonal;
441
+ let descriptor;
442
+ if (interpersonal >= q(0.80) && success)
443
+ descriptor = "exceptional";
444
+ else if (interpersonal >= q(0.60) && success)
445
+ descriptor = "good";
446
+ else if (success)
447
+ descriptor = "adequate";
448
+ else if (interpersonal >= q(0.40))
449
+ descriptor = "poor";
450
+ else
451
+ descriptor = "failure";
452
+ return {
453
+ quality_Q: interpersonal,
454
+ timeTaken_s: task.timeBase_s,
455
+ success,
456
+ descriptor,
457
+ details: { fearReduction_Q: mulDiv(interpersonal, q(0.30), SCALE.Q) },
458
+ };
459
+ }
460
+ // Detect deception - simplified
461
+ const interpersonal = getDomainIntelligence(actor, "interpersonal");
462
+ return {
463
+ quality_Q: interpersonal,
464
+ timeTaken_s: task.timeBase_s,
465
+ success: interpersonal >= q(0.50),
466
+ descriptor: interpersonal >= q(0.70) ? "good" : interpersonal >= q(0.40) ? "adequate" : "poor",
467
+ details: { interpersonal_Q: interpersonal },
468
+ };
469
+ }
470
+ /**
471
+ * Resolve logical-mathematical tasks.
472
+ */
473
+ function resolveLogicalMathematical(actor, task, action) {
474
+ const category = task.taskId.includes("fortification")
475
+ ? "fortification"
476
+ : task.taskId.includes("siege")
477
+ ? "mechanism"
478
+ : "weapon";
479
+ const spec = {
480
+ category: category,
481
+ complexity_Q: task.difficulty_Q,
482
+ timeBudget_h: task.timeBase_s / 3600,
483
+ };
484
+ const result = resolveEngineering(actor, spec, action.seed);
485
+ return {
486
+ quality_Q: result.qualityMul,
487
+ timeTaken_s: result.timeTaken_h * 3600,
488
+ success: result.descriptor !== "failure",
489
+ descriptor: result.descriptor,
490
+ details: { qualityMul: result.qualityMul, latentFlaw: result.latentFlaw },
491
+ };
492
+ }
493
+ /**
494
+ * Resolve musical tasks.
495
+ */
496
+ function resolveMusical(actor, task, action) {
497
+ if (task.taskId.includes("compose")) {
498
+ // Composition is simpler - just check musical skill vs difficulty
499
+ const musical = getDomainIntelligence(actor, "musical");
500
+ const rng = makeRng(action.seed, SCALE.Q);
501
+ const roll = rng.q01();
502
+ const difficultyPenalty = mulDiv(task.difficulty_Q, q(0.30), SCALE.Q);
503
+ const effectiveSkill = clampQ((musical - difficultyPenalty), q(0), SCALE.Q);
504
+ const success = roll < effectiveSkill;
505
+ let descriptor;
506
+ if (effectiveSkill >= q(0.85) && success)
507
+ descriptor = "exceptional";
508
+ else if (effectiveSkill >= q(0.65) && success)
509
+ descriptor = "good";
510
+ else if (success)
511
+ descriptor = "adequate";
512
+ else if (effectiveSkill >= q(0.40))
513
+ descriptor = "poor";
514
+ else
515
+ descriptor = "failure";
516
+ return {
517
+ quality_Q: effectiveSkill,
518
+ timeTaken_s: task.timeBase_s,
519
+ success,
520
+ descriptor,
521
+ details: { compositionQuality_Q: effectiveSkill },
522
+ };
523
+ }
524
+ if (task.taskId.includes("signal")) {
525
+ // Formation signaling - simplified without needing a listener
526
+ const musical = getDomainIntelligence(actor, "musical");
527
+ let descriptor;
528
+ if (musical >= q(0.80))
529
+ descriptor = "exceptional";
530
+ else if (musical >= q(0.60))
531
+ descriptor = "good";
532
+ else if (musical >= q(0.40))
533
+ descriptor = "adequate";
534
+ else if (musical >= q(0.25))
535
+ descriptor = "poor";
536
+ else
537
+ descriptor = "failure";
538
+ return {
539
+ quality_Q: musical,
540
+ timeTaken_s: task.timeBase_s,
541
+ success: musical >= q(0.40),
542
+ descriptor,
543
+ details: { signalClarity_Q: musical },
544
+ };
545
+ }
546
+ // Performance
547
+ const spec = {
548
+ performanceType: "rally",
549
+ duration_s: task.timeBase_s,
550
+ audienceCount: 5,
551
+ range_m: 50,
552
+ };
553
+ const result = resolvePerformance(actor, spec);
554
+ return {
555
+ quality_Q: mulDiv(result.fearDecayBonus_Q, SCALE.Q, q(0.020)),
556
+ timeTaken_s: task.timeBase_s,
557
+ success: result.descriptor !== "poor",
558
+ descriptor: result.descriptor,
559
+ details: { fearDecayBonus_Q: result.fearDecayBonus_Q, willpowerDrained: result.willpowerDrained_J },
560
+ };
561
+ }
562
+ /**
563
+ * Resolve intrapersonal tasks.
564
+ */
565
+ function resolveIntrapersonal(actor, task, action) {
566
+ const intrapersonal = getDomainIntelligence(actor, "intrapersonal");
567
+ if (task.taskId.includes("meditate")) {
568
+ // Meditation restores willpower
569
+ const willpowerRestored = Math.round((intrapersonal / SCALE.Q) * 5000 * (task.timeBase_s / 1800));
570
+ let descriptor;
571
+ if (intrapersonal >= q(0.80))
572
+ descriptor = "exceptional";
573
+ else if (intrapersonal >= q(0.60))
574
+ descriptor = "good";
575
+ else if (intrapersonal >= q(0.40))
576
+ descriptor = "adequate";
577
+ else
578
+ descriptor = "poor";
579
+ return {
580
+ quality_Q: intrapersonal,
581
+ timeTaken_s: task.timeBase_s,
582
+ success: true,
583
+ descriptor,
584
+ details: { willpowerRestored },
585
+ };
586
+ }
587
+ // Resist temptation
588
+ const rng = makeRng(action.seed, SCALE.Q);
589
+ const roll = rng.q01();
590
+ const difficultyPenalty = mulDiv(task.difficulty_Q, q(0.30), SCALE.Q);
591
+ const effectiveWillpower = clampQ((intrapersonal - difficultyPenalty), q(0), SCALE.Q);
592
+ const success = roll < effectiveWillpower;
593
+ let descriptor;
594
+ if (success && effectiveWillpower >= q(0.70))
595
+ descriptor = "exceptional";
596
+ else if (success)
597
+ descriptor = "good";
598
+ else if (effectiveWillpower >= q(0.40))
599
+ descriptor = "adequate";
600
+ else
601
+ descriptor = "failure";
602
+ return {
603
+ quality_Q: effectiveWillpower,
604
+ timeTaken_s: task.timeBase_s,
605
+ success,
606
+ descriptor,
607
+ details: { resistanceStrength_Q: effectiveWillpower },
608
+ };
609
+ }
610
+ // ── Main Router ───────────────────────────────────────────────────────────────
611
+ /**
612
+ * Resolve a competence action.
613
+ *
614
+ * This is the main entry point for the Phase 40 competence framework.
615
+ * It routes to the appropriate domain-specific resolver and computes
616
+ * XP gain for Phase 21 integration.
617
+ *
618
+ * @param actor - The entity performing the action.
619
+ * @param action - The competence action specification.
620
+ * @param world - The world state (for finding targets, etc.).
621
+ * @returns Competence outcome with quality, XP, and narrative.
622
+ */
623
+ export function resolveCompetence(actor, action, world) {
624
+ // Look up task
625
+ const task = getTaskById(action.taskId);
626
+ if (!task) {
627
+ return {
628
+ domain: action.domain,
629
+ quality_Q: q(0),
630
+ timeTaken_s: 0,
631
+ success: false,
632
+ descriptor: "failure",
633
+ xpGained: 0,
634
+ narrativeLine: `Unknown task: ${action.taskId}`,
635
+ };
636
+ }
637
+ // Route to domain-specific resolver
638
+ let result;
639
+ switch (task.domain) {
640
+ case "bodilyKinesthetic":
641
+ result = resolveBodilyKinesthetic(actor, task, action);
642
+ break;
643
+ case "spatial":
644
+ result = resolveSpatial(actor, task, action);
645
+ break;
646
+ case "naturalist":
647
+ result = resolveNaturalist(actor, task, action);
648
+ break;
649
+ case "interSpecies":
650
+ result = resolveInterSpecies(actor, task, action, world);
651
+ break;
652
+ case "linguistic":
653
+ result = resolveLinguistic(actor, task, action, world);
654
+ break;
655
+ case "interpersonal":
656
+ result = resolveInterpersonal(actor, task, action, world);
657
+ break;
658
+ case "logicalMathematical":
659
+ result = resolveLogicalMathematical(actor, task, action);
660
+ break;
661
+ case "musical":
662
+ result = resolveMusical(actor, task, action);
663
+ break;
664
+ case "intrapersonal":
665
+ result = resolveIntrapersonal(actor, task, action);
666
+ break;
667
+ default:
668
+ result = {
669
+ quality_Q: q(0.50),
670
+ timeTaken_s: task.timeBase_s,
671
+ success: true,
672
+ descriptor: "adequate",
673
+ details: {},
674
+ };
675
+ }
676
+ // Calculate XP
677
+ const xpGained = calculateXP(result.descriptor, task.difficulty_Q);
678
+ // Generate narrative if requested
679
+ const narrativeLine = action.narrative
680
+ ? generateNarrative(task, { ...result, domain: action.domain, xpGained }, actor)
681
+ : undefined;
682
+ return {
683
+ domain: action.domain,
684
+ quality_Q: result.quality_Q,
685
+ timeTaken_s: result.timeTaken_s,
686
+ success: result.success,
687
+ descriptor: result.descriptor,
688
+ xpGained,
689
+ narrativeLine,
690
+ details: result.details,
691
+ };
692
+ }
693
+ // ── Utility Exports ───────────────────────────────────────────────────────────
694
+ export { getDomainIntelligence, canonicalizeDescriptor, calculateXP };
@@ -0,0 +1,12 @@
1
+ export * from "./crafting.js";
2
+ export * from "./navigation.js";
3
+ export * from "./naturalist.js";
4
+ export * from "./interspecies.js";
5
+ export * from "./language.js";
6
+ export * from "./teaching.js";
7
+ export * from "./willpower.js";
8
+ export * from "./engineering.js";
9
+ export * from "./acoustic.js";
10
+ export * from "./performance.js";
11
+ export * from "./catalogue.js";
12
+ export * from "./framework.js";