feat(vida): página "Dia a dia" com as decisões e o porquê
Cada decisão tomada com base no que ele aprendeu passa a ser guardada com o motivo (aprendizado.decidir, até 800, persistidas): - acordou do cochilo antes da hora: "às 18h de quarta costuma ter gente, pelo plano que você contou"; - cochilo com a casa vazia, com a duração e o porquê; - sensor segurado numa hora em que acordou à toa (no máximo 1 nota a cada 10 min); - gesto escolhido porque costuma agradar (chance ≥ ×1,3); - fechamento do dia: horas com gente, carinhos e quanto o dia conferiu com o plano; - análise da IA (adotada ou sugestão, com a porcentagem) e rotina contada por você. esperado_e_fonte diz de onde veio a expectativa (plano seu, plano da IA, o que viu naquele dia da semana ou média). GET /aprendizado/dia devolve um dia: medido × plano por hora, conferência do dia, resumo e decisões. Painel: tela "Dia a dia" (#/dia-a-dia) com navegação entre dias, os números do dia, as faixas "Viu" × "Esperava" e a linha do tempo das decisões; atalho no cartão "O que ele aprendeu", no Ctrl+K e no guia. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -336,6 +336,64 @@ class SemanaTest(unittest.TestCase):
|
||||
v.visto_em = em(14, 9)
|
||||
atos = [v.agir(em(14, 10) + i * 120) for i in range(10)]
|
||||
self.assertIn('atividade dormir', atos)
|
||||
cochilo = next(d for d in self.a.decisoes if d['tipo'] == 'cochilo')
|
||||
self.assertEqual(cochilo['motivo'], 'às 10h de quarta a casa costuma ficar vazia, pelo plano que você contou')
|
||||
|
||||
|
||||
class DiaADiaTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.tmp = tempfile.TemporaryDirectory()
|
||||
self.a = Aprendizado(Path(self.tmp.name) / 'ap.json')
|
||||
self.a.ia, self.a.pode_ia = (lambda provedor, prompt, schema: plano_certo()), (lambda provedor: True)
|
||||
self.a.config['analise_ia'] = False
|
||||
self.v = Vida(Path(self.tmp.name) / 'v.json', iniciar=False, rng=random.Random(2))
|
||||
self.v.aprendizado = self.a
|
||||
self.v.enfileirar = lambda ordem: None
|
||||
|
||||
def tearDown(self):
|
||||
self.tmp.cleanup()
|
||||
|
||||
def test_cada_decisao_guarda_o_porque(self):
|
||||
semana_tipica(self.a)
|
||||
self.a.analisar(em(19, 1))
|
||||
self.assertEqual(self.a.decisoes[0]['tipo'], 'ia')
|
||||
self.assertIn('plano adotado: confere', self.a.decisoes[0]['motivo'])
|
||||
# acordar antes da chegada (quarta, 17h50)
|
||||
self.v.dormindo_proprio = True
|
||||
self.v.necessidades['energia'] = 70
|
||||
self.assertEqual(self.v.agir(em(14, 17, 50)), 'acordar')
|
||||
self.assertEqual(self.a.decisoes[0]['motivo'], 'às 18h de quarta costuma ter gente, pelo plano da IA')
|
||||
# sensor segurado numa hora em que acordou à toa
|
||||
self.a.falsos[22] = 1.0
|
||||
self.v.pir_acorda(em(14, 22))
|
||||
self.v.pir_acorda(em(14, 22) + 30) # a 2ª nota em menos de 10 min não repete
|
||||
notas = [d for d in self.a.decisoes if d['tipo'] == 'sono']
|
||||
self.assertEqual(len(notas), 1)
|
||||
self.assertIn('pede 1 movimento a mais', notas[0]['motivo'])
|
||||
|
||||
def test_fechar_o_dia_resume_e_confere_com_o_plano(self):
|
||||
self.a.informar('Fico fora de terça a quinta, das 8h às 18h')
|
||||
semana_tipica(self.a, semanas=1)
|
||||
fechou = [d for d in self.a.decisoes if d['tipo'] == 'dia']
|
||||
self.assertEqual(len(fechou), 7)
|
||||
quarta = next(d for d in fechou if 'quarta' in d['texto'])
|
||||
self.assertIn('conferiu 100% com o plano', quarta['motivo'])
|
||||
|
||||
def test_dia_a_dia_de_um_dia_passado_e_de_hoje(self):
|
||||
semana_tipica(self.a)
|
||||
self.a.analisar(em(19, 1))
|
||||
d = self.a.dia_a_dia('2026-10-14')
|
||||
self.assertEqual(d['nome_dia'], 'quarta')
|
||||
self.assertFalse(d['hoje'])
|
||||
self.assertLess(d['medido'][10], 0.3)
|
||||
self.assertEqual(d['plano'][2], dict(ini=8, fim=18, tipo='fora'))
|
||||
self.assertEqual(d['confere'], 1.0)
|
||||
self.assertTrue(any(x['tipo'] == 'dia' for x in d['decisoes']))
|
||||
self.assertIn('2026-10-05', d['dias'])
|
||||
hoje = self.a.dia_a_dia()
|
||||
self.assertTrue(hoje['hoje'])
|
||||
with self.assertRaises(ValueError):
|
||||
self.a.dia_a_dia('ontem')
|
||||
|
||||
|
||||
class RotasTest(unittest.TestCase):
|
||||
|
||||
Reference in New Issue
Block a user