Complementando...
O ASCII original só tinha 128 caracteres. Aí perceberam que tinha mais 128 "sobrando", e que ainda sim caberia em um byte.
Vários tiveram essa ideia ao mesmo tempo e cada um criou seu próprio mapeamento - como vc disse, cada valor entre 128 e 255 poderia ser um caractere completamente diferente, dependendo do mapeamento.
Esses mapeamentos eram chamados de code pages, e foram criados vários (ISO-8859-1 é um dentre as dezenas de code pages existentes).
Fiz um post bem detalhado sobre isso aqui.
Quanto ao Unicode, concordo que ele deveria ser menos bagunçado. Há muitos blocos de miscelaneous, que agrupam caracteres que não tem relação nenhuma entre si, fora a zona que virou os emojis.
Já sobre o fato de nem todas as fontes suportarem todos os caracteres, eu fico meio dividido. Por um lado, entendo que o Unicode está mais preocupado em organizar a bagunça que é esse monte de caracteres usados no mundo todo, então cada um que se vire pra dar o suporte adequado a cada nova versão que sai. Por outro lado, talvez devesse ter uma preocupação a mais com esse aspecto (os "clientes diretos" do Unicode).
Mas acho que é algo difícil de gerenciar e resolver: imagine se além dos problemas que eles já tem, ainda tivessem que dar suporte para todas as fontes existentes. Enfim...
Quem vem primeiro em ordem alfabética crescente? José < Josi
Depende. Cada idioma possui uma regra diferente, alguns colocam as letras acentuadas depois. E também podem ter casos em que eu precise de uma ordem específica e customizada.
Inclusive, muitas linguagens/bibliotecas possuem opções para configurar estas regras. Mais detalhes aqui.
Como ficará a conversão para maiúsculas dos nomes? José => JOSÉ
Também depende, cada idioma possui suas regras. Em alguns a versão maiúscula ou minúscula muda dependendo da posição da letra na palavra. Outros não se limitam a ter maiúsculas e minúsculas e possuem uma terceira forma chamada titlecase. E em outros idiomas, como o japonês, sequer existem os conceitos de "letra maiúscula e minúscula".
Sei que nada disso se aplica ao seu exemplo, foi só pra ilustrar que quando estamos falando de caracteres, temos que definir bem o escopo. Se for "somente textos em português", por exemplo, aí as regras que vc descreveu se encaixam perfeitamente. Contexto é tudo.
Se procurar por Jose o programa vai encontrar? José = Jose
Também depende do contexto. Se eu procurar pela palavra "sabia", também deveria encontrar "sabiá" e "sábia"?
Se for nome próprio, piorou, pois existe Fabio sem acento por exemplo, então neste caso seria melhor diferenciar de Fábio pra não trazer muitos falsos positivos.
Enfim, não dá pra cravar regras absolutas nem pra essas coisas que parecem "óbvias". Sempre depende do contexto.
Hoje a maioria das linguagens mainstream possui um suporte adequado ao Unicode e também permite configurar os detalhes que mencionei acima.
Quanto ao código Ruby que converte a string para bytes, vale lembrar que o resultado depende do encoding usado. Pelo jeito o Ruby usa UTF-8 por default. Mas veja como dá diferença se usar outro (código em Python):
s = "José"
for enc in ("utf-8", "utf-16", "latin1", "utf-32"):
print(f"{enc} - {','.join(map(str, s.encode(enc)))}")
A saída é:
utf-8 - 74,111,115,195,169
utf-16 - 255,254,74,0,111,0,115,0,233,0
latin1 - 74,111,115,233
utf-32 - 255,254,0,0,74,0,0,0,111,0,0,0,115,0,0,0,233,0,0,0
Por fim, concordo com e reforço a sua afirmação de que a ideia de "1 caractere = 1 byte" está ultrapassada há muito tempo (e me espanta como a esmagadora maioria dos cursos ignora esse fato, é só ver a quantidade de devs que chega ao mercado sem ter a menor noção disso).