1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
|
<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="pt-br">
<title>Tesseras - Notícias</title>
<subtitle>Rede P2P para preservar memórias humanas através dos milênios</subtitle>
<link rel="self" type="application/atom+xml" href="https://tesseras.net/pt-br/news/atom.xml"/>
<link rel="alternate" type="text/html" href="https://tesseras.net/pt-br/news/"/>
<generator uri="https://www.getzola.org/">Zola</generator>
<updated>2026-02-16T10:00:00+00:00</updated>
<id>https://tesseras.net/pt-br/news/atom.xml</id>
<entry xml:lang="pt-br">
<title>Empacotando o Tesseras para Debian</title>
<published>2026-02-16T10:00:00+00:00</published>
<updated>2026-02-16T10:00:00+00:00</updated>
<author>
<name>
Unknown
</name>
</author>
<link rel="alternate" type="text/html" href="https://tesseras.net/pt-br/news/packaging-debian/"/>
<id>https://tesseras.net/pt-br/news/packaging-debian/</id>
<content type="html" xml:base="https://tesseras.net/pt-br/news/packaging-debian/"><p>O Tesseras agora inclui um pacote <code>.deb</code> para Debian e Ubuntu. Este post explica
como compilar e instalar o pacote a partir do código-fonte usando <code>cargo-deb</code>.</p>
<h2 id="pre-requisitos">Pré-requisitos</h2>
<p>Você precisa de uma toolchain Rust funcional e das bibliotecas de sistema
necessárias:</p>
<pre><code data-lang="sh">sudo apt install build-essential pkg-config libsqlite3-dev
rustup toolchain install stable
cargo install cargo-deb
</code></pre>
<h2 id="compilando">Compilando</h2>
<p>Clone o repositório e execute a recipe <code>just deb</code>:</p>
<pre><code data-lang="sh">git clone https://git.sr.ht/~ijanc/tesseras
cd tesseras
just deb
</code></pre>
<p>Essa recipe faz três coisas:</p>
<ol>
<li><strong>Compila</strong> <code>tesd</code> (o daemon) e <code>tes</code> (o CLI) em modo release com
<code>cargo build --release</code></li>
<li><strong>Gera completions de shell</strong> para bash, zsh e fish a partir do binário <code>tes</code></li>
<li><strong>Empacota</strong> tudo em um arquivo <code>.deb</code> com
<code>cargo deb -p tesseras-daemon --no-build</code></li>
</ol>
<p>O resultado é um arquivo <code>.deb</code> em <code>target/debian/</code>.</p>
<h2 id="instalando">Instalando</h2>
<pre><code data-lang="sh">sudo dpkg -i target/debian/tesseras-daemon_*.deb
</code></pre>
<p>Se houver dependências faltando, corrija com:</p>
<pre><code data-lang="sh">sudo apt install -f
</code></pre>
<h2 id="configuracao-pos-instalacao">Configuração pós-instalação</h2>
<p>O script <code>postinst</code> cria automaticamente um usuário de sistema <code>tesseras</code> e o
diretório de dados <code>/var/lib/tesseras</code>. Para usar o CLI sem sudo, adicione seu
usuário ao grupo:</p>
<pre><code data-lang="sh">sudo usermod -aG tesseras $USER
</code></pre>
<p>Faça logout e login novamente, depois inicie o daemon:</p>
<pre><code data-lang="sh">sudo systemctl enable --now tesd
</code></pre>
<h2 id="o-que-o-pacote-inclui">O que o pacote inclui</h2>
<table><thead><tr><th>Caminho</th><th>Descrição</th></tr></thead><tbody>
<tr><td><code>/usr/bin/tesd</code></td><td>Daemon do nó completo</td></tr>
<tr><td><code>/usr/bin/tes</code></td><td>Cliente CLI</td></tr>
<tr><td><code>/etc/tesseras/config.toml</code></td><td>Configuração padrão (marcado como conffile)</td></tr>
<tr><td><code>/lib/systemd/system/tesd.service</code></td><td>Unit systemd com hardening de segurança</td></tr>
<tr><td>Completions de shell</td><td>bash, zsh e fish</td></tr>
</tbody></table>
<h2 id="como-o-cargo-deb-funciona">Como o cargo-deb funciona</h2>
<p>Os metadados de empacotamento ficam em <code>crates/tesseras-daemon/Cargo.toml</code> na
seção <code>[package.metadata.deb]</code>. Essa seção define:</p>
<ul>
<li><strong>depends</strong> — dependências em tempo de execução: <code>libc6</code> e <code>libsqlite3-0</code></li>
<li><strong>assets</strong> — arquivos incluídos no pacote (binários, config, unit systemd,
completions de shell)</li>
<li><strong>conf-files</strong> — arquivos tratados como configuração (preservados na
atualização)</li>
<li><strong>maintainer-scripts</strong> — scripts <code>postinst</code> e <code>postrm</code> em
<code>packaging/debian/scripts/</code></li>
<li><strong>systemd-units</strong> — integração automática com systemd</li>
</ul>
<p>O script <code>postinst</code> cria o usuário de sistema <code>tesseras</code> e o diretório de dados
na instalação. O script <code>postrm</code> remove o usuário, grupo e diretório de dados
apenas no <code>purge</code> (não na remoção simples).</p>
<h2 id="hardening-do-systemd">Hardening do systemd</h2>
<p>A unit <code>tesd.service</code> inclui diretivas de hardening de segurança:</p>
<pre><code data-lang="ini">NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/var/lib/tesseras
PrivateTmp=true
PrivateDevices=true
ProtectKernelTunables=true
ProtectControlGroups=true
RestrictSUIDSGID=true
MemoryDenyWriteExecute=true
</code></pre>
<p>O daemon roda como o usuário não-privilegiado <code>tesseras</code> e só pode escrever em
<code>/var/lib/tesseras</code>.</p>
<h2 id="deploy-para-um-servidor-remoto">Deploy para um servidor remoto</h2>
<p>O justfile inclui uma recipe <code>deploy</code> para enviar o <code>.deb</code> a um host remoto:</p>
<pre><code data-lang="sh">just deploy bootstrap1.tesseras.net
</code></pre>
<p>Isso compila o <code>.deb</code>, copia via <code>scp</code>, instala com <code>dpkg -i</code> e reinicia o
serviço <code>tesd</code>.</p>
<h2 id="atualizando">Atualizando</h2>
<p>Depois de baixar novas mudanças, basta rodar <code>just deb</code> novamente e reinstalar:</p>
<pre><code data-lang="sh">git pull
just deb
sudo dpkg -i target/debian/tesseras-daemon_*.deb
</code></pre>
</content>
</entry>
<entry xml:lang="pt-br">
<title>Empacotando o Tesseras para Arch Linux</title>
<published>2026-02-16T09:00:00+00:00</published>
<updated>2026-02-16T09:00:00+00:00</updated>
<author>
<name>
Unknown
</name>
</author>
<link rel="alternate" type="text/html" href="https://tesseras.net/pt-br/news/packaging-archlinux/"/>
<id>https://tesseras.net/pt-br/news/packaging-archlinux/</id>
<content type="html" xml:base="https://tesseras.net/pt-br/news/packaging-archlinux/"><p>O Tesseras agora inclui um PKGBUILD para Arch Linux. Este post explica como
compilar e instalar o pacote a partir do código-fonte.</p>
<h2 id="pre-requisitos">Pré-requisitos</h2>
<p>Você precisa de uma toolchain Rust funcional e do grupo base-devel:</p>
<pre><code data-lang="sh">sudo pacman -S --needed base-devel sqlite
rustup toolchain install stable
</code></pre>
<h2 id="compilando">Compilando</h2>
<p>Clone o repositório e execute a recipe <code>just arch</code>:</p>
<pre><code data-lang="sh">git clone https://git.sr.ht/~ijanc/tesseras
cd tesseras
just arch
</code></pre>
<p>Isso executa <code>makepkg -sf</code> dentro de <code>packaging/archlinux/</code>, que:</p>
<ol>
<li><strong>prepare</strong> — baixa as dependências Cargo com <code>cargo fetch --locked</code></li>
<li><strong>build</strong> — compila <code>tesd</code> e <code>tes</code> (o CLI) em modo release</li>
<li><strong>package</strong> — instala binários, serviço systemd, configs sysusers/tmpfiles,
completions de shell (bash, zsh, fish) e um arquivo de configuração padrão</li>
</ol>
<p>O resultado é um arquivo <code>.pkg.tar.zst</code> em <code>packaging/archlinux/</code>.</p>
<h2 id="instalando">Instalando</h2>
<pre><code data-lang="sh">sudo pacman -U packaging/archlinux/tesseras-*.pkg.tar.zst
</code></pre>
<h2 id="configuracao-pos-instalacao">Configuração pós-instalação</h2>
<p>O pacote cria automaticamente um usuário e grupo de sistema <code>tesseras</code> via
systemd-sysusers. Para usar o CLI sem sudo, adicione seu usuário ao grupo:</p>
<pre><code data-lang="sh">sudo usermod -aG tesseras $USER
</code></pre>
<p>Faça logout e login novamente, depois inicie o daemon:</p>
<pre><code data-lang="sh">sudo systemctl enable --now tesd
</code></pre>
<h2 id="o-que-o-pacote-inclui">O que o pacote inclui</h2>
<table><thead><tr><th>Caminho</th><th>Descrição</th></tr></thead><tbody>
<tr><td><code>/usr/bin/tesd</code></td><td>Daemon do nó completo</td></tr>
<tr><td><code>/usr/bin/tes</code></td><td>Cliente CLI</td></tr>
<tr><td><code>/etc/tesseras/config.toml</code></td><td>Configuração padrão (marcado como backup)</td></tr>
<tr><td><code>/usr/lib/systemd/system/tesd.service</code></td><td>Unit systemd com hardening de segurança</td></tr>
<tr><td><code>/usr/lib/sysusers.d/tesseras.conf</code></td><td>Definição do usuário de sistema</td></tr>
<tr><td><code>/usr/lib/tmpfiles.d/tesseras.conf</code></td><td>Diretório de dados <code>/var/lib/tesseras</code></td></tr>
<tr><td>Completions de shell</td><td>bash, zsh e fish</td></tr>
</tbody></table>
<h2 id="detalhes-do-pkgbuild">Detalhes do PKGBUILD</h2>
<p>O PKGBUILD compila diretamente a partir do checkout git local em vez de baixar
um tarball. A variável de ambiente <code>TESSERAS_ROOT</code> aponta o makepkg para a raiz
do workspace. O diretório target do Cargo é configurado para <code>$srcdir/target</code>
para manter os artefatos de build dentro do sandbox do makepkg.</p>
<p>O pacote depende apenas de <code>sqlite</code> em tempo de execução e <code>cargo</code> em tempo de
build.</p>
<h2 id="atualizando">Atualizando</h2>
<p>Depois de baixar novas mudanças, basta rodar <code>just arch</code> novamente e reinstalar:</p>
<pre><code data-lang="sh">git pull
just arch
sudo pacman -U packaging/archlinux/tesseras-*.pkg.tar.zst
</code></pre>
</content>
</entry>
<entry xml:lang="pt-br">
<title>Fase 4: Deduplicacao de Armazenamento</title>
<published>2026-02-15T23:00:00+00:00</published>
<updated>2026-02-15T23:00:00+00:00</updated>
<author>
<name>
Unknown
</name>
</author>
<link rel="alternate" type="text/html" href="https://tesseras.net/pt-br/news/phase4-storage-deduplication/"/>
<id>https://tesseras.net/pt-br/news/phase4-storage-deduplication/</id>
<content type="html" xml:base="https://tesseras.net/pt-br/news/phase4-storage-deduplication/"><p>Quando multiplas tesseras compartilham a mesma foto, o mesmo clipe de audio ou
os mesmos dados de fragmento, a camada de armazenamento antiga mantinha copias
separadas de cada. Em um no armazenando milhares de tesseras para a rede, essa
duplicacao se acumula rapidamente. A Fase 4 continua com deduplicacao de
armazenamento: um armazenamento enderecavel por conteudo (CAS) que garante que
cada dado unico seja armazenado exatamente uma vez em disco, independentemente
de quantas tesseras o referenciam.</p>
<p>O design e simples e comprovado: hash do conteudo com BLAKE3, usar o hash como
nome do arquivo e manter uma contagem de referencias no SQLite. Quando duas
tesseras incluem a mesma foto de 5 MB, um arquivo existe em disco com
refcount 2. Quando uma tessera e deletada, o refcount cai para 1 e o arquivo
permanece. Quando a ultima referencia e liberada, uma varredura periodica limpa
o orfao.</p>
<h2 id="o-que-foi-construido">O que foi construido</h2>
<p><strong>Migracao do esquema CAS</strong> (<code>tesseras-storage/migrations/004_dedup.sql</code>) — Tres
novas tabelas:</p>
<ul>
<li><code>cas_objects</code> — rastreia cada objeto no armazenamento: hash BLAKE3 (chave
primaria), tamanho em bytes, contagem de referencias e timestamp de criacao</li>
<li><code>blob_refs</code> — mapeia identificadores logicos de blobs (hash da tessera + hash
da memoria + nome do arquivo) para hashes CAS, substituindo a convencao antiga
de caminhos no sistema de arquivos</li>
<li><code>fragment_refs</code> — mapeia identificadores logicos de fragmentos (hash da
tessera + indice do fragmento) para hashes CAS, substituindo o antigo layout
do diretorio <code>fragments/</code></li>
</ul>
<p>Indices nas colunas de hash garantem lookups O(1) durante leituras e contagem de
referencias.</p>
<p><strong>CasStore</strong> (<code>tesseras-storage/src/cas.rs</code>) — O motor central de armazenamento
enderecavel por conteudo. Arquivos sao armazenados sob um diretorio de prefixo
de dois niveis: <code>&lt;raiz&gt;/&lt;prefixo-hex-2-chars&gt;/&lt;hash-completo&gt;.blob</code>. O
armazenamento fornece cinco operacoes:</p>
<ul>
<li><code>put(hash, data)</code> — escreve dados em disco se ainda nao presente, incrementa o
refcount. Retorna se ocorreu um hit de deduplicacao.</li>
<li><code>get(hash)</code> — le dados do disco pelo hash</li>
<li><code>release(hash)</code> — decrementa o refcount. Se chegar a zero, o arquivo em disco
e deletado imediatamente.</li>
<li><code>contains(hash)</code> — verifica existencia sem ler</li>
<li><code>ref_count(hash)</code> — retorna a contagem de referencias atual</li>
</ul>
<p>Todas as operacoes sao atomicas dentro de uma unica transacao SQLite. O refcount
e a fonte de verdade — se o refcount diz que o objeto existe, o arquivo deve
estar em disco.</p>
<p><strong>FsBlobStore com CAS</strong> (<code>tesseras-storage/src/blob.rs</code>) — Reescrito para
delegar todo armazenamento ao CAS. Quando um blob e escrito, seu hash BLAKE3 e
computado e passado para <code>cas.put()</code>. Uma linha em <code>blob_refs</code> mapeia o caminho
logico (tessera + memoria + arquivo) para o hash CAS. Leituras buscam o hash CAS
via <code>blob_refs</code> e leem de <code>cas.get()</code>. Deletar uma tessera libera todas as suas
referencias de blob em uma unica transacao.</p>
<p><strong>FsFragmentStore com CAS</strong> (<code>tesseras-storage/src/fragment.rs</code>) — Mesmo padrao
para fragmentos codificados com erasure coding. O checksum BLAKE3 de cada
fragmento ja e computado durante a codificacao Reed-Solomon, entao e usado
diretamente como chave CAS. A verificacao de fragmentos agora checa o hash CAS
ao inves de recomputar do zero — se o CAS diz que os dados estao intactos,
estao.</p>
<p><strong>Coletor de lixo sweep</strong> (<code>cas.rs:sweep()</code>) — Uma passagem periodica de GC que
trata tres casos limite que o caminho normal de refcount nao consegue:</p>
<ol>
<li><strong>Arquivos orfaos</strong> — arquivos em disco sem linha correspondente em
<code>cas_objects</code>. Pode acontecer apos um crash durante escrita. Arquivos com
menos de 1 hora sao pulados (periodo de graca para escritas em andamento);
orfaos mais antigos sao deletados.</li>
<li><strong>Refcounts vazados</strong> — linhas em <code>cas_objects</code> com refcount zero que nao
foram limpas (ex: se o processo morreu entre decrementar e deletar). Essas
linhas sao removidas.</li>
<li><strong>Idempotente</strong> — executar sweep duas vezes produz o mesmo resultado.</li>
</ol>
<p>O sweep e conectado ao loop de reparo existente em <code>tesseras-replication</code>, entao
roda automaticamente a cada 24 horas junto com as verificacoes de saude dos
fragmentos.</p>
<p><strong>Migracao do layout antigo</strong> (<code>tesseras-storage/src/migration.rs</code>) — Uma
estrategia de migracao copy-first que move dados do layout antigo baseado em
diretorios (<code>blobs/&lt;tessera&gt;/&lt;memoria&gt;/&lt;arquivo&gt;</code> e
<code>fragments/&lt;tessera&gt;/&lt;indice&gt;.shard</code>) para o CAS. A migracao:</p>
<ol>
<li>Verifica a versao de armazenamento em <code>storage_meta</code> (versao 1 = layout
antigo, versao 2 = CAS)</li>
<li>Percorre os diretorios antigos <code>blobs/</code> e <code>fragments/</code></li>
<li>Computa hashes BLAKE3 e insere no CAS via <code>put()</code> — duplicatas sao
automaticamente deduplicadas</li>
<li>Cria entradas correspondentes em <code>blob_refs</code> / <code>fragment_refs</code></li>
<li>Remove diretorios antigos somente apos todos os dados estarem seguros no CAS</li>
<li>Atualiza a versao de armazenamento para 2</li>
</ol>
<p>A migracao roda na inicializacao do daemon, e idempotente (segura para
re-executar) e reporta estatisticas: arquivos migrados, duplicatas encontradas,
bytes economizados.</p>
<p><strong>Metricas Prometheus</strong> (<code>tesseras-storage/src/metrics.rs</code>) — Dez novas metricas
para observabilidade:</p>
<table><thead><tr><th>Metrica</th><th>Descricao</th></tr></thead><tbody>
<tr><td><code>cas_objects_total</code></td><td>Total de objetos unicos no CAS</td></tr>
<tr><td><code>cas_bytes_total</code></td><td>Total de bytes armazenados</td></tr>
<tr><td><code>cas_dedup_hits_total</code></td><td>Numero de escritas que encontraram um objeto existente</td></tr>
<tr><td><code>cas_bytes_saved_total</code></td><td>Bytes economizados por deduplicacao</td></tr>
<tr><td><code>cas_gc_refcount_deletions_total</code></td><td>Objetos deletados quando refcount chegou a zero</td></tr>
<tr><td><code>cas_gc_sweep_orphans_cleaned_total</code></td><td>Arquivos orfaos removidos pelo sweep</td></tr>
<tr><td><code>cas_gc_sweep_leaked_refs_cleaned_total</code></td><td>Linhas de refcount vazadas limpas</td></tr>
<tr><td><code>cas_gc_sweep_skipped_young_total</code></td><td>Orfaos jovens pulados (periodo de graca)</td></tr>
<tr><td><code>cas_gc_sweep_duration_seconds</code></td><td>Tempo gasto no sweep GC</td></tr>
</tbody></table>
<p><strong>Testes baseados em propriedades</strong> — Dois testes proptest verificam invariantes
do CAS sob entradas aleatorias:</p>
<ul>
<li><code>refcount_matches_actual_refs</code> — apos N operacoes aleatorias de put/release, o
refcount sempre corresponde ao numero real de referencias pendentes</li>
<li><code>cas_path_is_deterministic</code> — o mesmo hash sempre produz o mesmo caminho no
sistema de arquivos</li>
</ul>
<p><strong>Atualizacao de testes de integracao</strong> — Todos os testes de integracao em
<code>tesseras-core</code>, <code>tesseras-replication</code>, <code>tesseras-embedded</code> e <code>tesseras-cli</code>
atualizados para os novos construtores com CAS. Testes de deteccao de
adulteracao atualizados para funcionar com o layout de diretorio CAS.</p>
<p>347 testes passam em todo o workspace. Clippy limpo com <code>-D warnings</code>.</p>
<h2 id="decisoes-de-arquitetura">Decisoes de arquitetura</h2>
<ul>
<li><strong>BLAKE3 como chave CAS</strong>: o hash de conteudo que ja computamos para
verificacao de integridade serve tambem como chave de deduplicacao. Nenhuma
etapa adicional de hashing — o hash computado durante <code>create</code> ou <code>replicate</code>
e reutilizado como endereco CAS.</li>
<li><strong>Refcount SQLite ao inves de reflinks do sistema de arquivos</strong>: consideramos
usar copy-on-write no nivel do sistema de arquivos (reflinks em btrfs/XFS),
mas isso amarraria o Tesseras a sistemas de arquivos especificos. Refcounting
em SQLite funciona em qualquer sistema de arquivos, incluindo FAT32 em
pendrives baratos e ext4 em Raspberry Pis.</li>
<li><strong>Diretorios de prefixo hexadecimal de dois niveis</strong>: armazenar todos os
objetos CAS em um diretorio plano desaceleraria sistemas de arquivos com
milhoes de entradas. A divisao <code>&lt;prefixo 2 chars&gt;/</code> limita qualquer diretorio
individual a ~65k entradas antes de um segundo nivel ser necessario. Isso
segue a abordagem usada pelo object store do Git.</li>
<li><strong>Periodo de graca para arquivos orfaos</strong>: o sweep GC pula arquivos com menos
de 1 hora para evitar deletar objetos sendo escritos por uma operacao
concorrente. Esta e uma escolha pragmatica — troca uma pequena janela de
potenciais orfaos por seguranca contra crashes sem exigir fsync ou commit de
duas fases.</li>
<li><strong>Migracao copy-first</strong>: a migracao copia dados para o CAS antes de remover
diretorios antigos. Se o processo for interrompido, os dados antigos
permanecem intactos e a migracao pode ser re-executada. Isso e mais lento que
mover arquivos mas garante zero perda de dados.</li>
<li><strong>Sweep no loop de reparo</strong>: ao inves de adicionar um timer separado de GC, o
sweep CAS aproveita o loop de reparo existente de 24 horas. Isso mantem o
daemon simples — um unico ciclo de manutencao em segundo plano cuida tanto da
saude dos fragmentos quanto da limpeza de armazenamento.</li>
</ul>
<h2 id="o-que-vem-a-seguir">O que vem a seguir</h2>
<ul>
<li><strong>Fase 4 continuacao</strong> — auditorias de seguranca, empacotamento para OS
(Alpine, Arch, Debian, OpenBSD, FreeBSD)</li>
<li><strong>Fase 5: Exploracao e Cultura</strong> — navegador publico de tesseras por
era/localizacao/tema/idioma, curadoria institucional, integracao genealogica
(FamilySearch, Ancestry), exportacao para midia fisica (M-DISC, microfilme,
papel livre de acido com QR), contexto assistido por IA</li>
</ul>
<p>A deduplicacao de armazenamento completa a historia de eficiencia de
armazenamento do Tesseras. Um no que armazena fragmentos para milhares de
usuarios — comum para nos institucionais e nos completos sempre ligados — agora
paga o custo de disco apenas por dados unicos. Combinado com codificacao de
apagamento Reed-Solomon (que ja minimiza redundancia no nivel da rede), o
sistema alcanca armazenamento eficiente tanto nas camadas local quanto
distribuida.</p>
</content>
</entry>
<entry xml:lang="pt-br">
<title>Fase 4: Onboarding de Nos Institucionais</title>
<published>2026-02-15T22:00:00+00:00</published>
<updated>2026-02-15T22:00:00+00:00</updated>
<author>
<name>
Unknown
</name>
</author>
<link rel="alternate" type="text/html" href="https://tesseras.net/pt-br/news/phase4-institutional-onboarding/"/>
<id>https://tesseras.net/pt-br/news/phase4-institutional-onboarding/</id>
<content type="html" xml:base="https://tesseras.net/pt-br/news/phase4-institutional-onboarding/"><p>Uma rede P2P composta apenas por individuos e fragil. Discos rigidos morrem,
celulares sao perdidos, pessoas perdem interesse. A sobrevivencia a longo prazo
das memorias da humanidade depende de instituicoes — bibliotecas, arquivos,
museus, universidades — que medem seus tempos de vida em seculos. A Fase 4
continua com o onboarding de nos institucionais: organizacoes verificadas agora
podem prometer armazenamento, manter indices de busca e participar da rede com
uma identidade distinta.</p>
<p>O design segue um principio de confiar mas verificar: instituicoes se
identificam via registros DNS TXT (o mesmo mecanismo usado por SPF, DKIM e DMARC
para email), prometem um orcamento de armazenamento e recebem isencoes de
reciprocidade para que possam armazenar fragmentos para outros sem esperar nada
em troca. Em contrapartida, a rede trata seus fragmentos como replicas de maior
qualidade e limita a dependencia excessiva de qualquer instituicao individual
atraves de restricoes de diversidade.</p>
<h2 id="o-que-foi-construido">O que foi construido</h2>
<p><strong>Bits de capacidade</strong> (<code>tesseras-core/src/network.rs</code>) — Dois novos flags
adicionados ao bitfield <code>Capabilities</code>: <code>INSTITUTIONAL</code> (bit 7) e <code>SEARCH_INDEX</code>
(bit 8). Um novo construtor <code>institutional_default()</code> retorna o conjunto
completo de capacidades da Fase 2 mais esses dois bits e <code>RELAY</code>. Nos normais
anunciam <code>phase2_default()</code> que nao inclui flags institucionais. Testes de
roundtrip de serializacao verificam que os novos bits sobrevivem a codificacao
MessagePack.</p>
<p><strong>Tipos de busca</strong> (<code>tesseras-core/src/search.rs</code>) — Tres novos tipos de dominio
para o subsistema de busca:</p>
<ul>
<li><code>SearchFilters</code> — parametros de consulta: <code>memory_type</code>, <code>visibility</code>,
<code>language</code>, <code>date_range</code>, <code>geo</code> (bounding box), <code>page</code>, <code>page_size</code></li>
<li><code>SearchHit</code> — um resultado individual: hash do conteudo mais um
<code>MetadataExcerpt</code> (titulo, descricao, tipo de memoria, data de criacao,
visibilidade, idioma, tags)</li>
<li><code>GeoFilter</code> — bounding box com <code>min_lat</code>, <code>max_lat</code>, <code>min_lon</code>, <code>max_lon</code> para
consultas espaciais</li>
</ul>
<p>Todos os tipos derivam <code>Serialize</code>/<code>Deserialize</code> para transporte e
<code>Clone</code>/<code>Debug</code> para diagnostico.</p>
<p><strong>Configuracao institucional do daemon</strong> (<code>tesd/src/config.rs</code>) — Uma nova secao
<code>[institutional]</code> no TOML com <code>domain</code> (o dominio DNS a verificar),
<code>pledge_bytes</code> (compromisso de armazenamento em bytes) e <code>search_enabled</code>
(toggle para o indice FTS5). O metodo <code>to_dht_config()</code> agora define
<code>Capabilities::institutional_default()</code> quando a configuracao institucional esta
presente, para que nos institucionais anunciem os bits de capacidade corretos em
respostas Pong.</p>
<p><strong>Verificacao DNS TXT</strong> (<code>tesd/src/institutional.rs</code>) — Resolucao DNS assincrona
usando <code>hickory-resolver</code> para verificar identidade institucional. O daemon
consulta registros TXT em <code>_tesseras.&lt;dominio&gt;</code> e analisa campos chave-valor:
<code>v</code> (versao), <code>node</code> (node ID em hexadecimal) e <code>pledge</code> (compromisso de
armazenamento em bytes). A verificacao checa:</p>
<ol>
<li>Um registro TXT existe em <code>_tesseras.&lt;dominio&gt;</code></li>
<li>O campo <code>node</code> corresponde ao node ID do proprio daemon</li>
<li>O campo <code>pledge</code> esta presente e e valido</li>
</ol>
<p>Na inicializacao, o daemon tenta a verificacao DNS. Se bem-sucedida, o no roda
com capacidades institucionais. Se falhar, o no registra um aviso e faz
downgrade para um no completo normal — sem crash, sem intervencao manual.</p>
<p><strong>Comando CLI de setup</strong> (<code>tesseras-cli/src/institutional.rs</code>) — Um novo
subcomando <code>institutional setup</code> que guia operadores pelo onboarding:</p>
<ol>
<li>Le a identidade do no a partir do diretorio de dados</li>
<li>Solicita nome de dominio e tamanho do pledge</li>
<li>Gera o registro DNS TXT exato a adicionar:
<code>v=tesseras1 node=&lt;hex&gt; pledge=&lt;bytes&gt;</code></li>
<li>Escreve a secao institucional no arquivo de configuracao do daemon</li>
<li>Imprime os proximos passos: adicionar o registro TXT, reiniciar o daemon</li>
</ol>
<p><strong>Indice de busca SQLite</strong> (<code>tesseras-storage</code>) — Uma migracao
(<code>003_institutional.sql</code>) que cria tres estruturas:</p>
<ul>
<li><code>search_content</code> — uma tabela virtual FTS5 para busca full-text sobre
metadados de tesseras (titulo, descricao, criador, tags, idioma)</li>
<li><code>geo_index</code> — uma tabela virtual R-tree para consultas espaciais de bounding
box sobre latitude/longitude</li>
<li><code>geo_map</code> — uma tabela de mapeamento ligando IDs de linhas do R-tree a hashes
de conteudo</li>
</ul>
<p>O adaptador <code>SqliteSearchIndex</code> implementa o port trait <code>SearchIndex</code> com
<code>index_tessera()</code> (inserir/atualizar) e <code>search()</code> (consultar com filtros).
Consultas FTS5 suportam busca em linguagem natural; consultas geo usam
<code>INTERSECT</code> do R-tree para lookups de bounding box. Resultados sao ranqueados
por score de relevancia do FTS5.</p>
<p>A migracao tambem adiciona uma coluna <code>is_institutional</code> a tabela <code>reciprocity</code>,
tratada de forma idempotente via checagens <code>pragma_table_info</code> (o
<code>ALTER TABLE ADD COLUMN</code> do SQLite nao tem <code>IF NOT EXISTS</code>).</p>
<p><strong>Bypass de reciprocidade</strong> (<code>tesseras-replication/src/service.rs</code>) — Nos
institucionais sao isentos de checagens de reciprocidade. Quando
<code>receive_fragment()</code> e chamado, se o node ID do remetente esta marcado como
institucional no ledger de reciprocidade, a checagem de saldo e ignorada
completamente. Isso significa que instituicoes podem armazenar fragmentos para
toda a rede sem precisar "ganhar" creditos primeiro — sua identidade verificada
por DNS e compromisso de armazenamento servem como credencial.</p>
<p><strong>Restricao de diversidade por tipo de no</strong>
(<code>tesseras-replication/src/distributor.rs</code>) — Uma nova funcao
<code>apply_institutional_diversity()</code> limita quantas replicas de uma unica tessera
podem ir para nos institucionais. O limite e <code>ceil(fator_replicacao / 3.5)</code> —
com o padrao <code>r=7</code>, no maximo 2 de 7 replicas vao para instituicoes. Isso impede
que a rede se torne dependente de um pequeno numero de grandes instituicoes: se
os servidores de uma universidade cairem, pelo menos 5 replicas permanecem em
nos independentes.</p>
<p><strong>Extensoes de mensagens DHT</strong> (<code>tesseras-dht/src/message.rs</code>) — Duas novas
variantes de mensagem:</p>
<table><thead><tr><th>Mensagem</th><th>Proposito</th></tr></thead><tbody>
<tr><td><code>Search</code></td><td>Cliente envia string de consulta, filtros e numero da pagina</td></tr>
<tr><td><code>SearchResult</code></td><td>No institucional responde com resultados e contagem total</td></tr>
</tbody></table>
<p>A funcao <code>encode()</code> foi trocada de serializacao MessagePack posicional para
nomeada (<code>rmp_serde::to_vec_named</code>) para lidar corretamente com campos opcionais
de <code>SearchFilters</code> — a codificacao posicional quebra quando
<code>skip_serializing_if</code> omite campos.</p>
<p><strong>Metricas Prometheus</strong> (<code>tesd/src/metrics.rs</code>) — Oito metricas especificas
institucionais:</p>
<ul>
<li><code>tesseras_institutional_pledge_bytes</code> — compromisso de armazenamento
configurado</li>
<li><code>tesseras_institutional_stored_bytes</code> — bytes realmente armazenados</li>
<li><code>tesseras_institutional_pledge_utilization_ratio</code> — razao armazenado/prometido</li>
<li><code>tesseras_institutional_peers_served</code> — peers unicos que receberam fragmentos</li>
<li><code>tesseras_institutional_search_index_total</code> — tesseras no indice de busca</li>
<li><code>tesseras_institutional_search_queries_total</code> — consultas de busca recebidas</li>
<li><code>tesseras_institutional_dns_verification_status</code> — 1 se verificado por DNS, 0
caso contrario</li>
<li><code>tesseras_institutional_dns_verification_last</code> — timestamp Unix da ultima
verificacao</li>
</ul>
<p><strong>Testes de integracao</strong> — Dois testes em
<code>tesseras-replication/tests/integration.rs</code>:</p>
<ul>
<li><code>institutional_peer_bypasses_reciprocity</code> — verifica que um peer institucional
com deficit massivo (-999.999 de saldo) ainda pode armazenar fragmentos,
enquanto um peer nao institucional com o mesmo deficit e rejeitado</li>
<li><code>institutional_node_accepts_fragment_despite_deficit</code> — teste async completo
usando <code>ReplicationService</code> com DHT, fragment store, reciprocity ledger e blob
store mockados: envia um fragmento de um remetente institucional e verifica
que e aceito</li>
</ul>
<p>322 testes passam em todo o workspace. Clippy limpo com <code>-D warnings</code>.</p>
<h2 id="decisoes-de-arquitetura">Decisoes de arquitetura</h2>
<ul>
<li><strong>DNS TXT ao inves de PKI ou blockchain</strong>: DNS e universalmente implantado,
universalmente compreendido e ja usado para verificacao de dominio (SPF, DKIM,
Let's Encrypt). Instituicoes ja gerenciam DNS. Nenhuma autoridade
certificadora, nenhum token, nenhuma transacao on-chain — apenas um registro
TXT. Se uma instituicao perder controle de seu dominio, a verificacao
naturalmente falha na proxima checagem.</li>
<li><strong>Degradacao graciosa em falha DNS</strong>: se a verificacao DNS falha na
inicializacao, o daemon faz downgrade para um no completo normal ao inves de
recusar iniciar. Isso previne incidentes operacionais — uma misconfiguracao
DNS nao deveria tirar um no do ar.</li>
<li><strong>Limite de diversidade em <code>ceil(r / 3.5)</code></strong>: com <code>r=7</code>, no maximo 2 replicas
vao para instituicoes. Isso e conservador — garante que a rede nunca dependa
de instituicoes para quorum majoritario, enquanto ainda se beneficia de sua
capacidade de armazenamento e uptime.</li>
<li><strong>Codificacao MessagePack nomeada</strong>: trocar de codificacao posicional para
nomeada adiciona ~15% de overhead por mensagem mas elimina uma classe de bugs
de serializacao quando campos opcionais estao presentes. O DHT nao e limitado
por largura de banda no nivel de mensagem, entao o tradeoff vale a pena.</li>
<li><strong>Isencao de reciprocidade ao inves de concessao de creditos</strong>: ao inves de
dar as instituicoes um saldo inicial grande de creditos (que e arbitrario e
precisa de ajuste), isentamos completamente. Sua identidade verificada por DNS
e compromisso publico de armazenamento substituem o mecanismo de reciprocidade
bilateral.</li>
<li><strong>FTS5 + R-tree no SQLite</strong>: busca full-text e indexacao espacial sao
embutidas no SQLite como extensoes carregaveis. Nenhum motor de busca externo
(Elasticsearch, Meilisearch) necessario. Isso mantem o deploy como um unico
binario com um unico arquivo de banco de dados — critico para operadores
institucionais que podem nao ter uma equipe de DevOps.</li>
</ul>
<h2 id="o-que-vem-a-seguir">O que vem a seguir</h2>
<ul>
<li><strong>Fase 4 continuacao</strong> — deduplicacao de armazenamento (armazenamento
enderecavel por conteudo com BLAKE3), auditorias de seguranca, empacotamento
para OS (Alpine, Arch, Debian, OpenBSD, FreeBSD)</li>
<li><strong>Fase 5: Exploracao e Cultura</strong> — navegador publico de tesseras por
era/localizacao/tema/idioma, curadoria institucional, integracao genealogica
(FamilySearch, Ancestry), exportacao para midia fisica (M-DISC, microfilme,
papel livre de acido com QR), contexto assistido por IA</li>
</ul>
<p>O onboarding institucional fecha uma lacuna critica no modelo de preservacao do
Tesseras. Nos individuais fornecem resiliencia de base — milhares de
dispositivos ao redor do globo, cada um armazenando alguns fragmentos. Nos
institucionais fornecem ancoragem — organizacoes com infraestrutura
profissional, armazenamento redundante e horizontes operacionais de multiplas
decadas. Juntos, formam uma rede onde memorias podem sobreviver tanto a
dispositivos individuais quanto a instituicoes individuais.</p>
</content>
</entry>
<entry xml:lang="pt-br">
<title>Fase 4: Tuning de Performance</title>
<published>2026-02-15T20:00:00+00:00</published>
<updated>2026-02-15T20:00:00+00:00</updated>
<author>
<name>
Unknown
</name>
</author>
<link rel="alternate" type="text/html" href="https://tesseras.net/pt-br/news/phase4-performance-tuning/"/>
<id>https://tesseras.net/pt-br/news/phase4-performance-tuning/</id>
<content type="html" xml:base="https://tesseras.net/pt-br/news/phase4-performance-tuning/"><p>Uma rede P2P que atravessa NATs mas engasga com seu proprio I/O nao serve de
muito. A Fase 4 continua com tuning de performance: centralizacao da
configuracao do banco de dados, cache de blobs de fragmentos em memoria,
gerenciamento de ciclo de vida de conexoes QUIC e eliminacao de leituras
desnecessarias de disco no hot path de atestacao.</p>
<p>O principio orientador foi o mesmo do resto do Tesseras: fazer a coisa mais
simples que realmente funciona. Sem alocadores customizados, sem estruturas de
dados lock-free, sem complexidade prematura. Um <code>StorageConfig</code> centralizado, um
cache LRU, um reaper de conexoes e uma correcao pontual para evitar reler blobs
que ja tinham checksum calculado.</p>
<h2 id="o-que-foi-construido">O que foi construido</h2>
<p><strong>Configuracao SQLite centralizada</strong> (<code>tesseras-storage/src/database.rs</code>) — Um
novo struct <code>StorageConfig</code> e funcoes <code>open_database()</code> / <code>open_in_memory()</code> que
aplicam todos os pragmas SQLite em um unico lugar: journal mode WAL, foreign
keys, modo synchronous (NORMAL por padrao, FULL para hardware instavel como
RPi + cartao SD), busy timeout, tamanho do cache de paginas e intervalo de
autocheckpoint WAL. Anteriormente, cada ponto de chamada abria uma conexao e
aplicava pragmas ad hoc. Agora o daemon, CLI e testes passam todos pelo mesmo
caminho. 7 testes cobrindo foreign keys, busy timeout, journal mode, migracoes,
modos synchronous e criacao de arquivos WAL em disco.</p>
<p><strong>Cache LRU de fragmentos</strong> (<code>tesseras-storage/src/cache.rs</code>) — Um
<code>CachedFragmentStore</code> que envolve qualquer <code>FragmentStore</code> com um cache LRU
ciente de bytes. Blobs de fragmentos sao cacheados na leitura e invalidados na
escrita ou exclusao. Quando o cache excede seu limite de bytes configurado, as
entradas menos recentemente usadas sao removidas. O cache e transparente: ele
proprio implementa <code>FragmentStore</code>, entao o resto da pilha nao sabe que esta la.
Metricas Prometheus opcionais rastreiam hits, misses e uso atual de bytes. 3
testes: hit no cache evita leitura interna, store invalida cache, remocao quando
excede bytes maximos.</p>
<p><strong>Metricas Prometheus de storage</strong> (<code>tesseras-storage/src/metrics.rs</code>) — Um
struct <code>StorageMetrics</code> com tres contadores/gauges: <code>fragment_cache_hits</code>,
<code>fragment_cache_misses</code> e <code>fragment_cache_bytes</code>. Registrado no registry
Prometheus e conectado ao cache de fragmentos via <code>with_metrics()</code>.</p>
<p><strong>Correcao do hot path de atestacao</strong> (<code>tesseras-replication/src/service.rs</code>) —
O fluxo de atestacao anteriormente lia cada blob de fragmento do disco e
recalculava seu checksum BLAKE3. Como <code>list_fragments()</code> ja retorna <code>FragmentId</code>
com um checksum armazenado, a correcao e trivial: usar <code>frag.checksum</code> ao inves
de <code>blake3::hash(&amp;data)</code>. Isso elimina uma leitura de disco por fragmento
durante atestacao — para uma tessera com 100 fragmentos, sao 100 leituras a
menos. Um teste com <code>expect_read_fragment().never()</code> verifica que nenhuma
leitura de blob acontece durante atestacao.</p>
<p><strong>Ciclo de vida do pool de conexoes QUIC</strong>
(<code>tesseras-net/src/quinn_transport.rs</code>) — Um struct <code>PoolConfig</code> controlando
maximo de conexoes, timeout de inatividade e intervalo do reaper.
<code>PooledConnection</code> envolve cada <code>quinn::Connection</code> com um timestamp
<code>last_used</code>. Quando o pool atinge capacidade maxima, a conexao inativa mais
antiga e removida antes de abrir uma nova. Uma tarefa reaper em background
(Tokio spawn) periodicamente fecha conexoes que ficaram inativas alem do
timeout. 4 novas metricas de pool: <code>tesseras_conn_pool_size</code>, <code>pool_hits_total</code>,
<code>pool_misses_total</code>, <code>pool_evictions_total</code>.</p>
<p><strong>Integracao no daemon</strong> (<code>tesd/src/config.rs</code>, <code>main.rs</code>) — Uma nova secao
<code>[performance]</code> na configuracao TOML com campos para tamanho de cache SQLite,
modo synchronous, busy timeout, tamanho de cache de fragmentos, maximo de
conexoes, timeout de inatividade e intervalo do reaper. O <code>main()</code> do daemon
agora chama <code>open_database()</code> com o <code>StorageConfig</code> configurado, envolve
<code>FsFragmentStore</code> com <code>CachedFragmentStore</code> e vincula QUIC com o <code>PoolConfig</code>
configurado. A dependencia direta de <code>rusqlite</code> foi removida do crate do daemon.</p>
<p><strong>Migracao do CLI</strong> (<code>tesseras-cli/src/commands/init.rs</code>, <code>create.rs</code>) — Ambos
os comandos <code>init</code> e <code>create</code> agora usam <code>tesseras_storage::open_database()</code> com
o <code>StorageConfig</code> padrao ao inves de abrir conexoes <code>rusqlite</code> diretamente. A
dependencia de <code>rusqlite</code> foi removida do crate do CLI.</p>
<h2 id="decisoes-de-arquitetura">Decisoes de arquitetura</h2>
<ul>
<li><strong>Padrao decorator para cache</strong>: <code>CachedFragmentStore</code> envolve
<code>Box&lt;dyn FragmentStore&gt;</code> e implementa <code>FragmentStore</code> ele proprio. Isso
significa que cache e opt-in, composavel e invisivel para consumidores. O
daemon habilita; testes podem pular.</li>
<li><strong>Remocao ciente de bytes</strong>: o cache LRU rastreia bytes totais, nao contagem
de entradas. Blobs de fragmentos variam muito em tamanho (um fragmento de
texto de 4KB vs um shard de foto de 2MB), entao contar entradas daria uma
visao enganosa do uso de memoria.</li>
<li><strong>Sem crate de pool de conexoes</strong>: ao inves de trazer uma biblioteca generica
de pool, o pool de conexoes e um wrapper fino sobre
<code>DashMap&lt;SocketAddr, PooledConnection&gt;</code> com um reaper Tokio. Conexoes QUIC sao
multiplexadas, entao o "pool" e realmente sobre gerenciamento de ciclo de vida
(limpeza de inativos, maximo de conexoes) e nao sobre emprestar/devolver.</li>
<li><strong>Checksums armazenados ao inves de releituras</strong>: a correcao de atestacao e
intencionalmente minima — uma linha alterada, uma leitura de disco removida
por fragmento. Os checksums ja estavam armazenados no SQLite por
<code>store_fragment()</code>, apenas nao estavam sendo usados.</li>
<li><strong>Configuracao centralizada de pragmas</strong>: um unico struct <code>StorageConfig</code>
substitui chamadas <code>PRAGMA</code> espalhadas. O flag <code>sqlite_synchronous_full</code>
existe especificamente para implantacoes em Raspberry Pi onde o kernel pode
crashar e perder transacoes WAL nao checkpointadas.</li>
</ul>
<h2 id="o-que-vem-a-seguir">O que vem a seguir</h2>
<ul>
<li><strong>Fase 4 continuacao</strong> — Shamir's Secret Sharing para herdeiros, tesseras
seladas (criptografia time-lock), auditorias de seguranca, onboarding de nos
institucionais, deduplicacao de storage, empacotamento para OS</li>
<li><strong>Fase 5: Exploracao e Cultura</strong> — navegador publico de tesseras por
era/localizacao/tema/idioma, curadoria institucional, integracao genealogica,
exportacao para midia fisica (M-DISC, microfilme, papel livre de acido com QR)</li>
</ul>
<p>Com tuning de performance implementado, Tesseras lida com o caso comum de forma
eficiente: leituras de fragmentos acertam o cache LRU, atestacao pula I/O de
disco, conexoes QUIC inativas sao removidas automaticamente e o SQLite e
configurado consistentemente em toda a pilha. Os proximos passos focam em
funcionalidades criptograficas (Shamir, time-lock) e hardening para implantacao
em producao.</p>
</content>
</entry>
<entry xml:lang="pt-br">
<title>Fase 4: Verificar Sem Instalar Nada</title>
<published>2026-02-15T20:00:00+00:00</published>
<updated>2026-02-15T20:00:00+00:00</updated>
<author>
<name>
Unknown
</name>
</author>
<link rel="alternate" type="text/html" href="https://tesseras.net/pt-br/news/phase4-wasm-browser-verification/"/>
<id>https://tesseras.net/pt-br/news/phase4-wasm-browser-verification/</id>
<content type="html" xml:base="https://tesseras.net/pt-br/news/phase4-wasm-browser-verification/"><p>Confiança não deveria exigir instalação de software. Se alguém te envia uma
tessera — um pacote de memórias preservadas — você deveria poder verificar que é
genuína e não foi modificada sem baixar um app, criar uma conta, ou confiar em
um servidor. É isso que o <code>tesseras-wasm</code> entrega: arraste um arquivo tessera
para uma página web, e a verificação criptográfica acontece inteiramente no seu
navegador.</p>
<h2 id="o-que-foi-construido">O que foi construído</h2>
<p><strong>tesseras-wasm</strong> — Um crate Rust que compila para WebAssembly via wasm-pack,
expondo quatro funções stateless para JavaScript. O crate depende do
<code>tesseras-core</code> para parsing do manifesto e chama primitivas criptográficas
diretamente (blake3, ed25519-dalek) ao invés de depender do <code>tesseras-crypto</code>,
que puxa bibliotecas pós-quânticas baseadas em C que não compilam para
<code>wasm32-unknown-unknown</code>.</p>
<p><code>parse_manifest</code> recebe os bytes brutos do MANIFEST (texto UTF-8 plano, não
MessagePack), delega para <code>tesseras_core::manifest::Manifest::parse()</code>, e
retorna uma string JSON com a chave pública Ed25519 do criador, caminhos dos
arquivos de assinatura, e uma lista de arquivos com seus hashes BLAKE3
esperados, tamanhos e tipos MIME. Structs internas (<code>ManifestJson</code>,
<code>CreatorPubkey</code>, <code>SignatureFiles</code>, <code>FileEntry</code>) são serializadas com serde_json.
Os campos de chave pública ML-DSA e arquivo de assinatura estão presentes no
contrato JSON mas definidos como <code>null</code> — prontos para quando a assinatura
pós-quântica for implementada no lado nativo.</p>
<p><code>hash_blake3</code> computa um hash BLAKE3 de bytes arbitrários e retorna uma string
hexadecimal de 64 caracteres. É chamada uma vez por arquivo na tessera para
verificar integridade contra o MANIFEST.</p>
<p><code>verify_ed25519</code> recebe uma mensagem, uma assinatura de 64 bytes e uma chave
pública de 32 bytes, constrói uma <code>ed25519_dalek::VerifyingKey</code>, e retorna se a
assinatura é válida. A validação de comprimento retorna erros descritivos
("Ed25519 public key must be 32 bytes") ao invés de causar panic.</p>
<p><code>verify_ml_dsa</code> é um stub que retorna um erro explicando que verificação ML-DSA
ainda não está disponível. Isso é deliberado: o crate <code>ml-dsa</code> no crates.io está
na v0.1.0-rc.7 (pré-release), e o <code>tesseras-crypto</code> usa <code>pqcrypto-dilithium</code>
(CRYSTALS-Dilithium baseado em C) que é incompatível em nível de bytes com FIPS
204 ML-DSA. Ambos os lados precisam usar a mesma implementação em Rust puro
antes que a verificação cruzada funcione. Verificação Ed25519 é suficiente —
toda tessera é assinada com Ed25519.</p>
<p>Todas as quatro funções usam um padrão de duas camadas para testabilidade:
funções internas retornam <code>Result&lt;T, String&gt;</code> e são testadas nativamente,
enquanto wrappers finos <code>#[wasm_bindgen]</code> convertem erros para <code>JsError</code>. Isso
evita que <code>JsError::new()</code> cause panic em targets não-WASM durante os testes.</p>
<p>O binário WASM compilado tem 109 KB bruto e 44 KB com gzip — bem abaixo do
orçamento de 200 KB. O wasm-opt aplica otimização <code>-Oz</code> após o wasm-pack
compilar com <code>opt-level = "z"</code>, LTO e uma única unidade de codegen.</p>
<p><strong>@tesseras/verify</strong> — Um pacote npm TypeScript (<code>crates/tesseras-wasm/js/</code>) que
orquestra a verificação no lado do navegador. A API pública é uma única função:</p>
<pre><code data-lang="typescript">async function verifyTessera(
archive: Uint8Array,
onProgress?: (current: number, total: number, file: string) =&gt; void
): Promise&lt;VerificationResult&gt;
</code></pre>
<p>O tipo <code>VerificationResult</code> fornece tudo que uma UI precisa: validade geral,
hash da tessera, chaves públicas do criador, status das assinaturas
(valid/invalid/missing para Ed25519 e ML-DSA), resultados de integridade por
arquivo com hashes esperados e reais, uma lista de arquivos inesperados não
presentes no MANIFEST, e um array de erros.</p>
<p>A descompactação de arquivos (<code>unpack.ts</code>) lida com três formatos: tar
comprimido com gzip (detectado pelos magic bytes <code>\x1f\x8b</code>, descomprimido com
fflate e depois parseado como tar), ZIP (magic <code>PK\x03\x04</code>, descompactado com
<code>unzipSync</code> do fflate), e tar bruto (<code>ustar</code> no offset 257). Uma função
<code>normalizePath</code> remove o prefixo <code>tessera-&lt;hash&gt;/</code> para que os caminhos internos
correspondam às entradas do MANIFEST.</p>
<p>A verificação roda em um Web Worker (<code>worker.ts</code>) para manter a thread da UI
responsiva. O worker inicializa o módulo WASM, descompacta o arquivo, parseia o
MANIFEST, verifica a assinatura Ed25519 contra a chave pública do criador,
depois faz hash de cada arquivo com BLAKE3 e compara com os valores esperados.
Mensagens de progresso são transmitidas de volta para a thread principal após
cada arquivo. Se qualquer assinatura é inválida, a verificação para
imediatamente sem fazer hash dos arquivos — falhando rápido na verificação mais
crítica.</p>
<p>O arquivo é transferido para o worker com zero-copy
(<code>worker.postMessage({ type: "verify", archive }, [archive.buffer])</code>) para
evitar duplicar arquivos de tessera potencialmente grandes na memória.</p>
<p><strong>Pipeline de build</strong> — Três novos targets no justfile: <code>wasm-build</code> executa
wasm-pack com <code>--target web --release</code> e otimiza com wasm-opt; <code>wasm-size</code>
reporta o tamanho do binário bruto e com gzip; <code>test-wasm</code> executa a suíte de
testes nativos.</p>
<p><strong>Testes</strong> — 9 testes unitários nativos cobrem hashing BLAKE3 (entrada vazia,
valor conhecido), verificação Ed25519 (assinatura válida, assinatura inválida,
chave errada, comprimento de chave inválido), e parsing do MANIFEST (manifesto
válido, UTF-8 inválido, lixo). 3 testes de integração WASM rodam em Chrome
headless via <code>wasm-pack test --headless --chrome</code>, verificando que
<code>hash_blake3</code>, <code>verify_ed25519</code> e <code>parse_manifest</code> funcionam corretamente quando
compilados para <code>wasm32-unknown-unknown</code>.</p>
<h2 id="decisoes-de-arquitetura">Decisões de arquitetura</h2>
<ul>
<li><strong>Sem dependência do tesseras-crypto</strong>: o crate WASM chama blake3 e
ed25519-dalek diretamente. O <code>tesseras-crypto</code> depende do <code>pqcrypto-kyber</code>
(ML-KEM baseado em C via pqcrypto-traits) que requer um toolchain de
compilador C e não tem target wasm32. Dependendo apenas de crates Rust puros,
o build WASM tem zero dependências C e compila sem problemas para WebAssembly.</li>
<li><strong>ML-DSA adiado, não fingido</strong>: ao invés de silenciosamente pular a
verificação pós-quântica, o stub retorna um erro explícito. Isso garante que
se uma tessera contiver uma assinatura ML-DSA, o resultado da verificação
reportará <code>ml_dsa: "missing"</code> ao invés de fingir que foi verificada. O
orquestrador JS lida com isso graciosamente — uma tessera é válida se Ed25519
passar e ML-DSA estiver ausente (ainda não implementado em nenhum dos lados).</li>
<li><strong>Padrão de função interna</strong>: <code>JsError</code> não pode ser construído em targets
não-WASM (causa panic). Dividir cada função em
<code>foo_inner() -&gt; Result&lt;T, String&gt;</code> e <code>foo() -&gt; Result&lt;T, JsError&gt;</code> permite que
a suíte de testes nativa exercite toda a lógica sem tocar em tipos JavaScript.
Os testes de integração WASM em Chrome headless testam a superfície completa
do <code>#[wasm_bindgen]</code>.</li>
<li><strong>Isolamento em Web Worker</strong>: operações criptográficas (especialmente BLAKE3
sobre arquivos de mídia grandes) podem levar centenas de milissegundos. Rodar
em um Worker previne travamentos na UI. O protocolo de progresso com streaming
(<code>{ type: "progress", current, total, file }</code>) permite que a UI mostre uma
barra de progresso durante a verificação de tesseras com muitos arquivos.</li>
<li><strong>Transferência zero-copy</strong>: <code>archive.buffer</code> é transferido para o Worker, não
copiado. Para um arquivo tessera de 50 MB, isso evita dobrar o uso de memória
durante a verificação.</li>
<li><strong>MANIFEST em texto plano, não MessagePack</strong>: o crate WASM parseia o mesmo
formato de MANIFEST em texto plano que o CLI. Isso é por design — o MANIFEST é
a Pedra de Rosetta da tessera, legível por qualquer pessoa com um editor de
texto. A dependência <code>rmp-serde</code> no Cargo.toml não é usada e será removida.</li>
</ul>
<h2 id="o-que-vem-a-seguir">O que vem a seguir</h2>
<ul>
<li><strong>Fase 4: Resiliência e Escala</strong> — Empacotamento para sistemas operacionais
(Alpine, Arch, Debian, FreeBSD, OpenBSD), CI no SourceHut e GitHub Actions,
auditorias de segurança, explorador de tesseras no navegador em tesseras.net
usando @tesseras/verify</li>
<li><strong>Fase 5: Exploração e Cultura</strong> — Navegador público de tesseras por
era/localização/tema/idioma, curadoria institucional, integração com
genealogia, exportação para mídia física (M-DISC, microfilme, papel livre de
ácido com QR)</li>
</ul>
<p>A verificação não exige mais confiança em software. Um arquivo tessera arrastado
para um navegador é verificado com o mesmo rigor criptográfico do CLI — mesmos
hashes BLAKE3, mesmas assinaturas Ed25519, mesmo parser de MANIFEST. A diferença
é que agora qualquer pessoa pode fazer isso.</p>
</content>
</entry>
<entry xml:lang="pt-br">
<title>Fase 4: Furando NATs</title>
<published>2026-02-15T18:00:00+00:00</published>
<updated>2026-02-15T18:00:00+00:00</updated>
<author>
<name>
Unknown
</name>
</author>
<link rel="alternate" type="text/html" href="https://tesseras.net/pt-br/news/phase4-nat-traversal/"/>
<id>https://tesseras.net/pt-br/news/phase4-nat-traversal/</id>
<content type="html" xml:base="https://tesseras.net/pt-br/news/phase4-nat-traversal/"><p>A maioria dos dispositivos das pessoas ficam atras de um NAT — um tradutor de
enderecos de rede que permite acessar a internet mas impede conexoes de entrada.
Para uma rede P2P, isso e um problema existencial: se dois nos atras de NATs nao
conseguem se comunicar, a rede se fragmenta. A Fase 4 continua com uma pilha
completa de travessia de NAT: descoberta via STUN, hole punching coordenado e
fallback por relay.</p>
<p>A abordagem segue o mesmo padrao da maioria dos sistemas P2P consolidados
(WebRTC, BitTorrent, IPFS): tente a opcao mais barata primeiro, escale apenas
quando necessario. Conectividade direta nao custa nada. Hole punching custa
alguns pacotes coordenados. Relay custa largura de banda sustentada de um
terceiro. Tesseras tenta nessa ordem.</p>
<h2 id="o-que-foi-construido">O que foi construido</h2>
<p><strong>Classificacao NatType</strong> (<code>tesseras-core/src/network.rs</code>) — Um novo enum
<code>NatType</code> (Public, Cone, Symmetric, Unknown) adicionado a camada de dominio
core. Esse tipo e compartilhado por toda a pilha: o cliente STUN o escreve, o
DHT o divulga em mensagens Pong, e o coordenador de punch o le para decidir se
hole punching vale a pena tentar (Cone-para-Cone funciona ~80% das vezes;
Symmetric-para-Symmetric quase nunca funciona).</p>
<p><strong>Cliente STUN</strong> (<code>tesseras-net/src/stun.rs</code>) — Uma implementacao STUN minima
(RFC 5389 Binding Request/Response) que descobre o endereco externo de um no. O
codec codifica requisicoes de 20 bytes com um ID de transacao aleatorio e
decodifica respostas XOR-MAPPED-ADDRESS. A funcao <code>discover_nat()</code> consulta
multiplos servidores STUN em paralelo (Google, Cloudflare por padrao), compara
os enderecos mapeados e classifica o tipo de NAT:</p>
<ul>
<li>Mesmo IP e porta de todos os servidores → <strong>Public</strong> (sem NAT)</li>
<li>Mesmo endereco mapeado de todos os servidores → <strong>Cone</strong> (hole punching
funciona)</li>
<li>Enderecos mapeados diferentes → <strong>Symmetric</strong> (hole punching nao confiavel)</li>
<li>Sem respostas → <strong>Unknown</strong></li>
</ul>
<p>Retentativas com backoff exponencial e timeouts configuraveis. 12 testes
cobrindo roundtrips de codec, todos os caminhos de classificacao e consultas
async em loopback.</p>
<p><strong>Coordenacao de punch assinada</strong> (<code>tesseras-net/src/punch.rs</code>) — Assinatura e
verificacao Ed25519 para mensagens <code>PunchIntro</code>, <code>RelayRequest</code> e
<code>RelayMigrate</code>. Cada introducao e assinada pelo iniciador com uma janela de
timestamp de 30 segundos, prevenindo ataques de reflexao (onde um atacante
reproduz uma introducao antiga para redirecionar trafego). O formato do payload
e <code>target || external_addr || timestamp</code> — alterar qualquer campo invalida a
assinatura. 6 testes unitarios mais 3 testes baseados em propriedades com
proptest (IDs de no, portas e tokens de sessao arbitrarios).</p>
<p><strong>Gerenciador de sessoes de relay</strong> (<code>tesseras-net/src/relay.rs</code>) — Gerencia
sessoes de relay UDP transparente entre nos com NAT. Cada sessao tem um token
aleatorio de 16 bytes; os nos prefixam seus pacotes com o token, o relay remove
e encaminha. Funcionalidades:</p>
<ul>
<li>Encaminhamento bidirecional (A→R→B e B→R→A)</li>
<li>Limite de taxa: 256 KB/s para nos reciprocos, 64 KB/s para nao reciprocos</li>
<li>Duracao maxima de 10 minutos para sessoes bootstrap (nao reciprocas)</li>
<li>Migracao de endereco: quando o IP de um no muda (Wi-Fi para celular), um
<code>RelayMigrate</code> assinado atualiza a sessao sem derruba-la</li>
<li>Limpeza por inatividade com timeout configuravel</li>
<li>8 testes unitarios mais 2 testes baseados em propriedades</li>
</ul>
<p><strong>Extensoes de mensagens DHT</strong> (<code>tesseras-dht/src/message.rs</code>) — Sete novas
variantes de mensagem adicionadas ao protocolo DHT:</p>
<table><thead><tr><th>Mensagem</th><th>Proposito</th></tr></thead><tbody>
<tr><td><code>PunchIntro</code></td><td>"Quero conectar ao no X, aqui esta meu endereco externo assinado"</td></tr>
<tr><td><code>PunchRequest</code></td><td>O introdutor encaminha a requisicao ao destino</td></tr>
<tr><td><code>PunchReady</code></td><td>O destino confirma prontidao, envia seu endereco externo</td></tr>
<tr><td><code>RelayRequest</code></td><td>"Crie uma sessao de relay para o no X"</td></tr>
<tr><td><code>RelayOffer</code></td><td>O relay responde com seu endereco e token de sessao</td></tr>
<tr><td><code>RelayClose</code></td><td>Encerrar uma sessao de relay</td></tr>
<tr><td><code>RelayMigrate</code></td><td>Atualizar sessao apos mudanca de rede</td></tr>
</tbody></table>
<p>A mensagem <code>Pong</code> foi estendida com metadados NAT: <code>nat_type</code>,
<code>relay_slots_available</code> e <code>relay_bandwidth_used_kbps</code>. Todos os novos campos
usam <code>#[serde(default)]</code> para compatibilidade retroativa — nos antigos ignoram o
que nao reconhecem, nos novos usam defaults. 9 novos testes de roundtrip de
serializacao.</p>
<p><strong>Trait NatHandler e dispatch</strong> (<code>tesseras-dht/src/engine.rs</code>) — Uma nova trait
async <code>NatHandler</code> (5 metodos) injetada no engine DHT, seguindo o mesmo padrao
de injecao de dependencia do <code>ReplicationHandler</code> existente. O loop de dispatch
de mensagens do engine agora roteia todas as mensagens punch/relay para o
handler. Isso mantem o engine DHT agnóstico ao protocolo enquanto permite que a
logica de travessia de NAT viva em <code>tesseras-net</code>.</p>
<p><strong>Tipos de reconexao mobile</strong> (<code>tesseras-embedded/src/reconnect.rs</code>) — Uma
maquina de estados de reconexao em tres fases para dispositivos moveis:</p>
<ol>
<li><strong>QuicMigration</strong> (0-2s) — tenta migracao de conexao QUIC para todos os peers
ativos</li>
<li><strong>ReStun</strong> (2-5s) — redescobre endereco externo via STUN</li>
<li><strong>ReEstablish</strong> (5-10s) — reconecta peers que a migracao nao conseguiu salvar</li>
</ol>
<p>Peers sao reconectados em ordem de prioridade: nos bootstrap primeiro, depois
nos que guardam nossos fragmentos, depois nos cujos fragmentos guardamos, depois
vizinhos DHT gerais. Uma nova variante de evento <code>NetworkChanged</code> foi adicionada
ao stream de eventos FFI para que o app Flutter possa mostrar progresso de
reconexao.</p>
<p><strong>Configuracao NAT do daemon</strong> (<code>tesd/src/config.rs</code>) — Uma nova secao <code>[nat]</code>
na configuracao TOML com lista de servidores STUN, toggle de relay, maximo de
sessoes relay, limites de largura de banda (reciproco vs bootstrap) e timeout de
inatividade. Todos os campos tem defaults sensiveis; relay e desabilitado por
padrao.</p>
<p><strong>Metricas Prometheus</strong> (<code>tesseras-net/src/metrics.rs</code>) — 16 metricas em quatro
subsistemas:</p>
<ul>
<li><strong>STUN</strong>: requisicoes, falhas, histograma de latencia</li>
<li><strong>Punch</strong>: tentativas/sucessos/falhas (por par de tipo NAT), histograma de
latencia</li>
<li><strong>Relay</strong>: sessoes ativas, sessoes totais, bytes encaminhados, timeouts por
inatividade, hits de rate limit</li>
<li><strong>Reconexao</strong>: mudancas de rede, tentativas/sucessos por fase, histograma de
duracao</li>
</ul>
<p>6 testes verificando registro, incremento, cardinalidade de labels e deteccao de
registro duplo.</p>
<p><strong>Testes de integracao</strong> — Dois testes end-to-end usando <code>MemTransport</code> (rede
simulada em memoria):</p>
<ul>
<li><code>punch_integration.rs</code> — Fluxo completo de hole-punch com 3 nos: A envia
<code>PunchIntro</code> assinado ao introdutor I, I verifica e encaminha <code>PunchRequest</code> a
B, B verifica a assinatura original e envia <code>PunchReady</code> de volta, A e B
trocam mensagens diretamente. Tambem testa que uma assinatura invalida e
corretamente rejeitada.</li>
<li><code>relay_integration.rs</code> — Fluxo completo de relay com 3 nos: A solicita relay
de R, R cria sessao e envia <code>RelayOffer</code> a ambos os peers, A e B trocam
pacotes prefixados com token atraves de R, A migra para um novo endereco no
meio da sessao, A fecha a sessao, e o teste verifica que a sessao e encerrada
e encaminhamento posterior falha.</li>
</ul>
<p><strong>Testes de propriedade</strong> — 7 testes baseados em proptest cobrindo: roundtrips
de assinatura para todos os tres tipos de mensagem assinada (IDs de no, portas e
tokens arbitrarios), determinismo de classificacao NAT (mesmas entradas sempre
produzem mesma saida), validade de binding request STUN, unicidade de tokens de
sessao, e rejeicao de pacotes curtos pelo relay.</p>
<p><strong>Alvos Justfile</strong> — <code>just test-nat</code> executa todos os testes de travessia NAT em
<code>tesseras-net</code> e <code>tesseras-dht</code>. <code>just test-chaos</code> e um placeholder para futuros
testes de caos com Docker Compose e <code>tc netem</code>.</p>
<h2 id="decisoes-de-arquitetura">Decisoes de arquitetura</h2>
<ul>
<li><strong>STUN ao inves de TURN</strong>: implementamos STUN (descoberta) e relay customizado
ao inves de TURN completo. TURN requer alocacao autenticada e foi projetado
para relay de midia; nosso relay e mais simples — encaminhamento UDP com
prefixo de token e limites de taxa. Isso mantem o protocolo minimo e evita
depender de servidores TURN externos.</li>
<li><strong>Assinaturas em introducoes</strong>: cada <code>PunchIntro</code> e assinado pelo iniciador.
Sem isso, um atacante poderia enviar introducoes forjadas para redirecionar as
tentativas de hole-punch de um no para um endereco controlado pelo atacante
(ataque de reflexao). A janela de timestamp de 30 segundos limita replay.</li>
<li><strong>Tiers reciprocos de largura de banda</strong>: nos relay dao 4x mais largura de
banda (256 vs 64 KB/s) para peers com boas pontuacoes de reciprocidade. Isso
incentiva nos a armazenar fragmentos para outros — se voce contribui, recebe
melhor servico de relay quando precisa.</li>
<li><strong>Extensao Pong retrocompativel</strong>: novos campos NAT em <code>Pong</code> usam
<code>#[serde(default)]</code> e <code>Option&lt;T&gt;</code>. Nos antigos que nao entendem esses campos
simplesmente os pulam durante deserializacao. Nenhum bump de versao de
protocolo necessario.</li>
<li><strong>NatHandler como trait async</strong>: a logica de travessia NAT e injetada no
engine DHT via trait, assim como <code>ReplicationHandler</code>. Isso mantem o engine
DHT focado em roteamento e gerenciamento de peers, e permite que a
implementacao NAT seja trocada ou desabilitada sem tocar no codigo core do
DHT.</li>
</ul>
<h2 id="o-que-vem-a-seguir">O que vem a seguir</h2>
<ul>
<li><strong>Fase 4 continuacao</strong> — tuning de performance (pooling de conexoes, cache de
fragmentos, SQLite WAL), auditorias de seguranca, onboarding de nos
institucionais, empacotamento para OS</li>
<li><strong>Fase 5: Exploracao e Cultura</strong> — navegador publico de tesseras por
era/localizacao/tema/idioma, curadoria institucional, integracao genealogica,
exportacao para midia fisica (M-DISC, microfilme, papel livre de acido com QR)</li>
</ul>
<p>Com travessia de NAT, Tesseras pode conectar nos independentemente de sua
topologia de rede. Nos publicos conversam diretamente. Nos com NAT Cone furam
com ajuda de um introdutor. Nos com NAT Symmetric ou firewalled usam relay
atraves de peers voluntarios. A rede se adapta ao mundo real, onde a maioria dos
dispositivos esta atras de um NAT e as condicoes de rede mudam constantemente.</p>
</content>
</entry>
<entry xml:lang="pt-br">
<title>CLI Encontra a Rede: Comandos Publish, Fetch e Status</title>
<published>2026-02-15T00:00:00+00:00</published>
<updated>2026-02-15T00:00:00+00:00</updated>
<author>
<name>
Unknown
</name>
</author>
<link rel="alternate" type="text/html" href="https://tesseras.net/pt-br/news/cli-daemon-rpc/"/>
<id>https://tesseras.net/pt-br/news/cli-daemon-rpc/</id>
<content type="html" xml:base="https://tesseras.net/pt-br/news/cli-daemon-rpc/"><p>Até agora o CLI operava isoladamente: criar uma tessera, verificar, exportar,
listar o que você tem. Tudo ficava na sua máquina. Com esta atualização, o <code>tes</code>
ganha três comandos que fazem a ponte entre o armazenamento local e a rede P2P —
<code>publish</code>, <code>fetch</code> e <code>status</code> — comunicando-se com um <code>tesd</code> em execução através
de um socket Unix.</p>
<h2 id="o-que-foi-construido">O que foi construído</h2>
<p><strong>Crate <code>tesseras-rpc</code></strong> — Um novo crate compartilhado entre CLI e daemon.
Define o protocolo RPC usando serialização MessagePack com enquadramento
prefixado por tamanho (cabeçalho big-endian de 4 bytes, máximo de 64 MiB). Três
tipos de requisição (<code>Publish</code>, <code>Fetch</code>, <code>Status</code>) e suas respostas
correspondentes. Um <code>DaemonClient</code> síncrono gerencia a conexão do socket Unix
com timeouts configuráveis. O protocolo é deliberadamente simples — uma
requisição, uma resposta, conexão fechada — para manter a implementação
auditável.</p>
<p><strong><code>tes publish &lt;hash&gt;</code></strong> — Publica uma tessera na rede. Aceita hashes completos
ou prefixos curtos (ex.: <code>tes publish a1b2</code>), que são resolvidos no banco de
dados local. O daemon lê todos os arquivos da tessera do armazenamento, empacota
em um único buffer MessagePack e entrega ao motor de replicação. Tesseras
pequenas (&lt; 4 MB) são replicadas como um único fragmento; maiores passam por
codificação de apagamento Reed-Solomon. A saída mostra o hash curto e a contagem
de fragmentos:</p>
<pre><code>Published tessera 9f2c4a1b (24 fragments created)
Distribution in progress — use `tes status 9f2c4a1b` to track.
</code></pre>
<p><strong><code>tes fetch &lt;hash&gt;</code></strong> — Busca uma tessera da rede usando o hash de conteúdo
completo. O daemon coleta fragmentos disponíveis localmente, reconstrói os dados
originais via decodificação de apagamento se necessário, desempacota os arquivos
e armazena no CAS (content-addressable store). Retorna o número de memórias e o
tamanho total buscado.</p>
<p><strong><code>tes status &lt;hash&gt;</code></strong> — Exibe a saúde de replicação de uma tessera. A saída
mapeia diretamente o modelo interno de saúde do motor de replicação:</p>
<table><thead><tr><th>Estado</th><th>Significado</th></tr></thead><tbody>
<tr><td>Local</td><td>Ainda não publicada — existe apenas na sua máquina</td></tr>
<tr><td>Publishing</td><td>Fragmentos sendo distribuídos, redundância crítica</td></tr>
<tr><td>Replicated</td><td>Distribuída, mas abaixo da redundância alvo</td></tr>
<tr><td>Healthy</td><td>Redundância completa alcançada</td></tr>
</tbody></table>
<p><strong>Listener RPC no daemon</strong> — O daemon agora escuta em um socket Unix (padrão:
<code>$XDG_RUNTIME_DIR/tesseras/daemon.sock</code>) com permissões de diretório adequadas
(0700), limpeza de sockets obsoletos e shutdown gracioso. Cada conexão é tratada
em uma task Tokio — o listener converte o stream assíncrono para I/O síncrono
para a camada de enquadramento, despacha para o handler RPC e escreve a resposta
de volta.</p>
<p><strong>Pack/unpack no <code>tesseras-core</code></strong> — Um módulo pequeno que serializa uma lista
de entradas de arquivo (caminho + dados) em um único buffer MessagePack e
vice-versa. Esta é a ponte entre a estrutura de diretórios da tessera e os blobs
opacos do motor de replicação.</p>
<h2 id="decisoes-de-arquitetura">Decisões de arquitetura</h2>
<ul>
<li><strong>Socket Unix ao invés de TCP</strong>: a comunicação RPC entre CLI e daemon acontece
na mesma máquina. Sockets Unix são mais rápidos, não precisam de alocação de
porta, e as permissões do sistema de arquivos fornecem controle de acesso sem
TLS.</li>
<li><strong>MessagePack ao invés de JSON</strong>: o mesmo formato wire usado em todo o
Tesseras. Compacto, sem schema, e já é uma dependência do workspace. Uma
ida-e-volta típica de publish request/response ocupa menos de 200 bytes.</li>
<li><strong>Cliente síncrono, daemon assíncrono</strong>: o <code>DaemonClient</code> usa I/O bloqueante
porque o CLI não precisa de concorrência — envia uma requisição e espera. O
listener do daemon é assíncrono (Tokio) para tratar múltiplas conexões. A
camada de enquadramento funciona com qualquer impl <code>Read</code>/<code>Write</code>, conectando
ambos os mundos.</li>
<li><strong>Resolução de prefixo no lado do cliente</strong>: <code>publish</code> e <code>status</code> resolvem
prefixos curtos localmente antes de enviar o hash completo ao daemon. Isso
mantém o daemon stateless — ele não precisa acessar o banco de dados do CLI.</li>
<li><strong>Alinhamento do diretório de dados padrão</strong>: o padrão do CLI mudou de
<code>~/.tesseras</code> para <code>~/.local/share/tesseras</code> (via <code>dirs::data_dir()</code>) para
coincidir com o daemon. Um aviso de migração é exibido quando dados no caminho
antigo são detectados.</li>
</ul>
<h2 id="proximos-passos">Próximos passos</h2>
<ul>
<li><strong>Contagem de peers no DHT</strong>: o comando <code>status</code> atualmente reporta 0 peers —
conectar a contagem real do DHT é o próximo passo</li>
<li><strong><code>tes show</code></strong>: exibir o conteúdo de uma tessera (memórias, metadados) sem
exportar</li>
<li><strong>Fetch com streaming</strong>: para tesseras grandes, transmitir fragmentos conforme
chegam ao invés de esperar por todos</li>
</ul>
</content>
</entry>
<entry xml:lang="pt-br">
<title>Fase 4: Recuperação de Chaves por Herdeiros com Shamir's Secret Sharing</title>
<published>2026-02-15T00:00:00+00:00</published>
<updated>2026-02-15T00:00:00+00:00</updated>
<author>
<name>
Unknown
</name>
</author>
<link rel="alternate" type="text/html" href="https://tesseras.net/pt-br/news/phase4-shamir-heir-recovery/"/>
<id>https://tesseras.net/pt-br/news/phase4-shamir-heir-recovery/</id>
<content type="html" xml:base="https://tesseras.net/pt-br/news/phase4-shamir-heir-recovery/"><p>O que acontece com suas memórias quando você morre? Até agora, Tesseras
conseguia preservar conteúdo ao longo de milênios — mas as chaves privadas e
seladas morriam com o dono. A Fase 4 continua com uma solução: Shamir's Secret
Sharing, um esquema criptográfico que permite dividir sua identidade em
fragmentos e distribuí-los para as pessoas em quem você mais confia.</p>
<p>A matemática é elegante: você escolhe um limiar T e um total N. Qualquer T
fragmentos reconstroem o segredo completo; T-1 fragmentos não revelam
absolutamente nada. Isso não é "quase nada" — é informação-teoricamente seguro.
Um atacante com um fragmento a menos que o limiar tem exatamente zero bits de
informação sobre o segredo, independentemente do poder computacional que tenha.</p>
<h2 id="o-que-foi-construido">O que foi construído</h2>
<p><strong>Aritmética de corpo finito GF(256)</strong> (<code>tesseras-crypto/src/shamir/gf256.rs</code>) —
Shamir's Secret Sharing requer aritmética em um corpo finito. Implementamos
GF(256) usando o mesmo polinômio irredutível do AES (x^8 + x^4 + x^3 + x + 1),
com tabelas de lookup para logaritmo e exponenciação computadas em tempo de
compilação. Todas as operações são em tempo constante via consulta a tabelas —
sem ramificações baseadas em dados secretos. O módulo inclui o método de Horner
para avaliação de polinômios e interpolação de Lagrange em x=0 para recuperação
do segredo. 233 linhas, exaustivamente testado: todos os 256 elementos para
propriedades de identidade/inverso, comutatividade e associatividade.</p>
<p><strong>ShamirSplitter</strong> (<code>tesseras-crypto/src/shamir/mod.rs</code>) — A API principal de
split/reconstruct. <code>split()</code> recebe uma fatia de bytes do segredo, uma
configuração (limiar T, total N) e a chave pública Ed25519 do dono. Para cada
byte do segredo, constrói um polinômio aleatório de grau T-1 sobre GF(256) com o
byte do segredo como termo constante, e então o avalia em N pontos distintos.
<code>reconstruct()</code> recebe T ou mais fragmentos e recupera o segredo via
interpolação de Lagrange. Ambas as operações incluem validação extensiva:
limites do limiar, consistência de sessão, correspondência de impressão digital
do dono e verificação de checksum BLAKE3.</p>
<p><strong>Formato HeirShare</strong> — Cada fragmento é um artefato autocontido e serializável
com:</p>
<ul>
<li>Versão do formato (v1) para compatibilidade futura</li>
<li>Índice do fragmento (1..N) e metadados de limiar/total</li>
<li>ID de sessão (8 bytes aleatórios) — impede mistura de fragmentos de sessões
diferentes</li>
<li>Impressão digital do dono (primeiros 8 bytes do hash BLAKE3 da chave pública
Ed25519)</li>
<li>Dados do fragmento (os y-values de Shamir, mesmo comprimento do segredo)</li>
<li>Checksum BLAKE3 sobre todos os campos anteriores</li>
</ul>
<p>Os fragmentos são serializados em dois formatos: <strong>MessagePack</strong> (binário
compacto, para uso programático) e <strong>texto base64</strong> (legível por humanos, para
impressão e armazenamento físico). O formato texto inclui um cabeçalho com
metadados e delimitadores:</p>
<pre><code>--- TESSERAS HEIR SHARE ---
Format: v1
Owner: a1b2c3d4e5f6a7b8 (fingerprint)
Share: 1 of 3 (threshold: 2)
Session: 9f8e7d6c5b4a3210
Created: 2026-02-15
&lt;dados MessagePack codificados em base64&gt;
--- END HEIR SHARE ---
</code></pre>
<p>Este formato é projetado para ser impresso em papel, armazenado em um cofre
bancário ou gravado em metal. O cabeçalho é informacional — apenas o payload
base64 é analisado durante a reconstrução.</p>
<p><strong>Integração com CLI</strong> (<code>tesseras-cli/src/commands/heir.rs</code>) — Três novos
subcomandos:</p>
<ul>
<li><code>tes heir create</code> — divide sua identidade Ed25519 em fragmentos de herdeiros.
Solicita confirmação (sua identidade completa está em jogo), gera arquivos
<code>.bin</code> e <code>.txt</code> para cada fragmento e escreve <code>heir_meta.json</code> no diretório de
identidade.</li>
<li><code>tes heir reconstruct</code> — carrega arquivos de fragmentos (detecta
automaticamente formato binário vs texto), valida consistência, reconstrói o
segredo, deriva o par de chaves Ed25519 e opcionalmente o instala em
<code>~/.tesseras/identity/</code> (com backup automático da identidade existente).</li>
<li><code>tes heir info</code> — exibe metadados do fragmento e verifica o checksum sem expor
nenhum material secreto.</li>
</ul>
<p><strong>Formato do blob secreto</strong> — As chaves de identidade são serializadas em um
blob versionado antes da divisão: um byte de versão (0x01), um byte de flags
(0x00 para somente Ed25519), seguido da chave secreta Ed25519 de 32 bytes. Isso
deixa espaço para expansão futura quando as chaves privadas X25519 e ML-KEM-768
forem integradas ao sistema de fragmentos de herdeiros.</p>
<p><strong>Testes</strong> — 20 testes unitários para ShamirSplitter (roundtrip, todas as
combinações de fragmentos, fragmentos insuficientes, dono errado, sessão errada,
limite threshold-1, segredos grandes até o tamanho de chave ML-KEM-768). 7
testes unitários para aritmética GF(256) (propriedades de campo exaustivas). 3
testes baseados em propriedades com proptest (segredos arbitrários até 5000
bytes, configurações T-de-N arbitrárias, verificação de segurança
informação-teórica). Testes de roundtrip de serialização para ambos os formatos
MessagePack e texto base64. 2 testes de integração cobrindo o ciclo de vida
completo de herdeiros: gerar identidade, dividir em fragmentos, serializar,
desserializar, reconstruir, verificar par de chaves e assinar/verificar com
chaves reconstruídas.</p>
<h2 id="decisoes-de-arquitetura">Decisões de arquitetura</h2>
<ul>
<li><strong>GF(256) ao invés de GF(primo)</strong>: usamos GF(256) ao invés de um corpo primo
porque ele mapeia naturalmente para bytes — cada elemento é um único byte,
cada fragmento tem o mesmo comprimento do segredo. Sem aritmética de inteiros
grandes, sem redução modular, sem padding. Esta é a mesma abordagem usada pela
maioria das implementações reais de Shamir, incluindo SSSS e Hashicorp Vault.</li>
<li><strong>Tabelas de lookup em tempo de compilação</strong>: as tabelas LOG e EXP para
GF(256) são computadas em tempo de compilação usando <code>const fn</code>. Isso
significa zero custo de inicialização em tempo de execução e operações em
tempo constante via consulta a tabelas ao invés de loops.</li>
<li><strong>ID de sessão previne mistura entre sessões</strong>: cada chamada a <code>split()</code> gera
um novo ID de sessão aleatório. Se um herdeiro acidentalmente usar fragmentos
de duas sessões diferentes de divisão (por exemplo, antes e depois de uma
rotação de chaves), a reconstrução falha de forma limpa com um erro de
validação ao invés de produzir dados corrompidos.</li>
<li><strong>Checksums BLAKE3 detectam corrupção</strong>: cada fragmento inclui um checksum
BLAKE3 sobre seu conteúdo. Isso captura degradação de bits, erros de
transmissão e truncamento acidental antes de qualquer tentativa de
reconstrução. Um fragmento impresso em papel e escaneado via OCR vai falhar no
checksum se um único caractere estiver errado.</li>
<li><strong>Impressão digital do dono para identificação</strong>: os fragmentos incluem os
primeiros 8 bytes de BLAKE3(chave pública Ed25519) como impressão digital.
Isso permite aos herdeiros verificar a qual identidade um fragmento pertence
sem revelar a chave pública completa. Durante a reconstrução, a impressão
digital é verificada contra a chave recuperada.</li>
<li><strong>Formato duplo para resiliência</strong>: ambos os formatos binário (MessagePack) e
texto (base64) são gerados porque mídias físicas têm modos de falha diferentes
de armazenamento digital. Um pendrive pode falhar; papel sobrevive. Um QR code
pode ficar ilegível; texto base64 pode ser digitado manualmente.</li>
<li><strong>Versionamento do blob</strong>: o segredo é envolvido em um blob versionado
(versão + flags + material de chave) para que versões futuras possam incluir
chaves adicionais (X25519, ML-KEM-768) sem quebrar compatibilidade com
fragmentos existentes.</li>
</ul>
<h2 id="o-que-vem-a-seguir">O que vem a seguir</h2>
<ul>
<li><strong>Fase 4 continuada: Resiliência e Escala</strong> — NAT traversal avançado
(STUN/TURN), ajuste de performance (pool de conexões, cache de fragmentos,
SQLite WAL), auditorias de segurança, integração de nós institucionais,
empacotamento para sistemas operacionais</li>
<li><strong>Fase 5: Exploração e Cultura</strong> — navegador público de tesseras por
era/localização/tema/idioma, curadoria institucional, integração com
genealogia, exportação para mídia física (M-DISC, microfilme, papel livre de
ácido com QR)</li>
</ul>
<p>Com Shamir's Secret Sharing, Tesseras fecha a última lacuna crítica na
preservação a longo prazo. Suas memórias sobrevivem a falhas de infraestrutura
através de erasure coding. Sua privacidade sobrevive a computadores quânticos
através de criptografia híbrida. E agora, sua identidade sobrevive a você —
passada adiante para as pessoas que você escolheu, exigindo a cooperação delas
para desbloquear o que você deixou para trás.</p>
</content>
</entry>
<entry xml:lang="pt-br">
<title>Fase 4: Criptografia e Tesseras Seladas</title>
<published>2026-02-14T16:00:00+00:00</published>
<updated>2026-02-14T16:00:00+00:00</updated>
<author>
<name>
Unknown
</name>
</author>
<link rel="alternate" type="text/html" href="https://tesseras.net/pt-br/news/phase4-encryption-sealed/"/>
<id>https://tesseras.net/pt-br/news/phase4-encryption-sealed/</id>
<content type="html" xml:base="https://tesseras.net/pt-br/news/phase4-encryption-sealed/"><p>Algumas memórias não são para todos. Um diário privado, uma carta para ser
aberta em 2050, um segredo de família selado até que os netos tenham idade
suficiente. Até agora, toda tessera na rede era aberta. A Fase 4 muda isso:
Tesseras agora criptografa conteúdo privado e selado com um esquema
criptográfico híbrido projetado para resistir tanto a ataques clássicos quanto
quânticos.</p>
<p>O princípio continua o mesmo — criptografar o mínimo possível. Memórias públicas
precisam de disponibilidade, não de sigilo. Mas quando alguém cria uma tessera
privada ou selada, o conteúdo agora é trancado por criptografia AES-256-GCM com
chaves protegidas por um mecanismo híbrido de encapsulamento de chaves
combinando X25519 e ML-KEM-768. Ambos os algoritmos precisam ser quebrados para
acessar o conteúdo.</p>
<h2 id="o-que-foi-construido">O que foi construído</h2>
<p><strong>Encriptador AES-256-GCM</strong> (<code>tesseras-crypto/src/encryption.rs</code>) — Criptografia
simétrica de conteúdo com nonces aleatórios de 12 bytes e dados autenticados
associados (AAD). O AAD vincula o texto cifrado ao seu contexto: para tesseras
privadas, o hash do conteúdo é incluído; para tesseras seladas, tanto o hash do
conteúdo quanto o timestamp <code>open_after</code> são vinculados no AAD. Isso significa
que mover texto cifrado entre tesseras com datas de abertura diferentes causa
falha na decriptação — você não consegue enganar o sistema para abrir uma
memória selada antecipadamente trocando o texto cifrado para uma tessera com uma
data de selo anterior.</p>
<p><strong>Mecanismo Híbrido de Encapsulamento de Chaves</strong> (<code>tesseras-crypto/src/kem.rs</code>)
— Troca de chaves usando X25519 (Diffie-Hellman clássico em curva elíptica)
combinado com ML-KEM-768 (o KEM pós-quântico baseado em reticulados padronizado
pelo NIST, anteriormente Kyber). Ambos os segredos compartilhados são combinados
via <code>blake3::derive_key</code> com uma string de contexto fixa ("tesseras hybrid kem
v1") para produzir uma única chave de criptografia de conteúdo de 256 bits. Isso
segue a mesma filosofia "dual desde o início" das assinaturas duplas do projeto
(Ed25519 + ML-DSA): se qualquer algoritmo for quebrado no futuro, o outro ainda
protege o conteúdo.</p>
<p><strong>Envelope de Chave Selada</strong> (<code>tesseras-crypto/src/sealed.rs</code>) — Encapsula uma
chave de criptografia de conteúdo usando o KEM híbrido, para que apenas o dono
da tessera possa recuperá-la. O KEM produz uma chave de transporte, que é XORed
com a chave de conteúdo para produzir uma chave encapsulada armazenada junto ao
texto cifrado do KEM. Ao desselar, o dono decapsula o texto cifrado do KEM para
recuperar a chave de transporte, depois faz XOR novamente para recuperar a chave
de conteúdo.</p>
<p><strong>Publicação de Chave</strong> (<code>tesseras-crypto/src/sealed.rs</code>) — Um artefato assinado
independente para publicar a chave de conteúdo de uma tessera selada após a data
<code>open_after</code> ter passado. O dono assina a chave de conteúdo, o hash da tessera e
o timestamp de publicação com suas chaves duais (Ed25519, com placeholder
ML-DSA). O manifesto permanece imutável — a publicação da chave é um documento
separado. Outros nós verificam a assinatura contra a chave pública do dono antes
de usar a chave publicada para decriptar o conteúdo.</p>
<p><strong>EncryptionContext</strong> (<code>tesseras-core/src/enums.rs</code>) — Um tipo de domínio que
representa o contexto AAD para criptografia. Ele vive em tesseras-core e não em
tesseras-crypto porque é um conceito de domínio (não um detalhe de implementação
criptográfica). O método <code>to_aad_bytes()</code> produz serialização determinística: um
byte de tag (0x00 para Private, 0x01 para Sealed), seguido do hash de conteúdo
e, para Sealed, o timestamp <code>open_after</code> como i64 little-endian.</p>
<p><strong>Validação de domínio</strong> (<code>tesseras-core/src/service.rs</code>) —
<code>TesseraService::create()</code> agora rejeita tesseras Sealed e Private que não
fornecem chaves de criptografia. Esta é uma validação no nível de domínio: a
camada de serviço garante que você não pode criar uma memória selada sem a
maquinaria criptográfica para protegê-la. A mensagem de erro é clara: "missing
encryption keys for visibility sealed until 2050-01-01."</p>
<p><strong>Atualizações de tipos do core</strong> — <code>TesseraIdentity</code> agora inclui um campo
opcional <code>encryption_public: Option&lt;HybridEncryptionPublic&gt;</code> contendo tanto as
chaves públicas X25519 quanto ML-KEM-768. <code>KeyAlgorithm</code> ganhou as variantes
<code>X25519</code> e <code>MlKem768</code>. O layout do sistema de arquivos de identidade agora
suporta <code>node.x25519.key</code>/<code>.pub</code> e <code>node.mlkem768.key</code>/<code>.pub</code>.</p>
<p><strong>Testes</strong> — 8 testes unitários para AES-256-GCM (roundtrip, chave errada, texto
cifrado adulterado, AAD errado, falha de decriptação cross-context, nonces
únicos, mais 2 testes baseados em propriedades para payloads arbitrários e
unicidade de nonces). 5 testes unitários para HybridKem (roundtrip, par de
chaves errado, X25519 adulterado, determinismo do KDF, mais 1 teste baseado em
propriedades). 4 testes unitários para SealedKeyEnvelope e KeyPublication. 2
testes de integração cobrindo o ciclo de vida completo de tesseras seladas e
privadas: gerar chaves, criar chave de conteúdo, criptografar, selar, desselar,
decriptar, publicar chave e verificar — o ciclo completo.</p>
<h2 id="decisoes-de-arquitetura">Decisões de arquitetura</h2>
<ul>
<li><strong>KEM híbrido desde o início</strong>: X25519 + ML-KEM-768 segue a mesma filosofia
das assinaturas duplas. Não sabemos quais suposições criptográficas se
manterão ao longo dos milênios, então combinamos algoritmos clássicos e
pós-quânticos. O custo é ~1,2 KB de material de chave adicional por identidade
— trivial comparado às fotos e vídeos em uma tessera.</li>
<li><strong>BLAKE3 para KDF</strong>: ao invés de adicionar <code>hkdf</code> + <code>sha2</code> como novas
dependências, usamos <code>blake3::derive_key</code> com uma string de contexto fixa. O
modo de derivação de chaves do BLAKE3 é especificamente projetado para este
caso de uso, e o projeto já depende do BLAKE3 para hashing de conteúdo.</li>
<li><strong>Manifestos imutáveis</strong>: quando a data <code>open_after</code> de uma tessera selada
passa, a chave de conteúdo é publicada como um artefato assinado separado
(<code>KeyPublication</code>), não modificando o manifesto. Isso preserva a natureza
append-only e endereçada por conteúdo das tesseras. O manifesto foi assinado
no momento da criação e nunca muda.</li>
<li><strong>Vinculação AAD previne troca de texto cifrado</strong>: o <code>EncryptionContext</code>
vincula tanto o hash de conteúdo quanto (para tesseras seladas) o timestamp
<code>open_after</code> nos dados autenticados do AES-GCM. Um atacante que copie conteúdo
criptografado de uma tessera "selada até 2050" para uma tessera "selada até
2025" vai descobrir que a decriptação falha — o AAD não corresponde mais.</li>
<li><strong>Encapsulamento de chave por XOR</strong>: o envelope de chave selada usa um XOR
simples da chave de conteúdo com a chave de transporte derivada do KEM, ao
invés de uma camada adicional de AES-GCM. Como a chave de transporte é um
valor aleatório fresco do KEM e é usada exatamente uma vez, o XOR é
informação-teoricamente seguro para este caso de uso específico e evita
complexidade desnecessária.</li>
<li><strong>Validação de domínio, não validação de storage</strong>: a verificação de "chaves
de criptografia ausentes" vive em <code>TesseraService::create()</code>, não na camada de
storage. Isso segue o padrão de arquitetura hexagonal: regras de domínio são
aplicadas na fronteira de serviço, não espalhadas pelos adaptadores.</li>
</ul>
<h2 id="o-que-vem-a-seguir">O que vem a seguir</h2>
<ul>
<li><strong>Fase 4 continuada: Resiliência e Escala</strong> — Shamir's Secret Sharing para
distribuição de chaves de herdeiros, NAT traversal avançado (STUN/TURN),
ajuste de performance, auditorias de segurança, empacotamento para sistemas
operacionais</li>
<li><strong>Fase 5: Exploração e Cultura</strong> — Navegador público de tesseras por
era/localização/tema/idioma, curadoria institucional, integração com
genealogia, exportação para mídia física (M-DISC, microfilme, papel livre de
ácido com QR)</li>
</ul>
<p>Tesseras seladas fazem do Tesseras uma verdadeira cápsula do tempo. Um pai agora
pode gravar uma mensagem para o neto que ainda não nasceu, selá-la até 2060 e
saber que o envelope criptográfico vai resistir — mesmo que os computadores
quânticos do futuro tentem abri-lo antes da hora.</p>
</content>
</entry>
<entry xml:lang="pt-br">
<title>Fase 3: Memórias nas Suas Mãos</title>
<published>2026-02-14T14:00:00+00:00</published>
<updated>2026-02-14T14:00:00+00:00</updated>
<author>
<name>
Unknown
</name>
</author>
<link rel="alternate" type="text/html" href="https://tesseras.net/pt-br/news/phase3-api-and-apps/"/>
<id>https://tesseras.net/pt-br/news/phase3-api-and-apps/</id>
<content type="html" xml:base="https://tesseras.net/pt-br/news/phase3-api-and-apps/"><p>As pessoas agora podem segurar suas memórias nas próprias mãos. A Fase 3 entrega
o que as fases anteriores construíram: um app mobile onde alguém baixa o
Tesseras, cria uma identidade, tira uma foto, e aquela memória entra na rede de
preservação. Sem contas na nuvem, sem assinaturas, sem nenhuma empresa entre
você e suas memórias.</p>
<h2 id="o-que-foi-construido">O que foi construído</h2>
<p><strong>tesseras-embedded</strong> — Um nó P2P completo que roda dentro de um app mobile. A
struct <code>EmbeddedNode</code> é dona de um runtime Tokio, banco SQLite, transporte QUIC,
engine Kademlia DHT, serviço de replicação e serviço de tessera — a mesma stack
do daemon desktop, compilada como biblioteca compartilhada. Um padrão singleton
global (<code>Mutex&lt;Option&lt;EmbeddedNode&gt;&gt;</code>) garante um único nó por ciclo de vida do
app. Ao iniciar, ele abre o banco de dados, executa migrações, carrega ou gera
uma identidade Ed25519 com proof-of-work para o node ID, faz bind QUIC numa
porta efêmera, conecta DHT e replicação, e inicia o loop de reparo. Ao parar,
envia um sinal de shutdown e drena graciosamente.</p>
<p>Onze funções FFI são expostas para Dart via flutter_rust_bridge: ciclo de vida
(<code>node_start</code>, <code>node_stop</code>, <code>node_is_running</code>), identidade (<code>create_identity</code>,
<code>get_identity</code>), memórias (<code>create_memory</code>, <code>get_timeline</code>, <code>get_memory</code>) e
status da rede (<code>get_network_stats</code>, <code>get_replication_status</code>). Todos os tipos
que cruzam a fronteira FFI são structs planas com apenas <code>String</code>,
<code>Option&lt;String&gt;</code>, <code>Vec&lt;String&gt;</code> e primitivos — sem trait objects, sem generics,
sem lifetimes.</p>
<p>Quatro módulos adaptadores fazem a ponte entre as ports do core e as
implementações concretas: <code>Blake3HasherAdapter</code>,
<code>Ed25519SignerAdapter</code>/<code>Ed25519VerifierAdapter</code> para criptografia,
<code>DhtPortAdapter</code> para operações DHT, e <code>ReplicationHandlerAdapter</code> para RPCs de
fragmentos e atestação recebidos.</p>
<p>A feature flag <code>bundled-sqlite</code> compila o SQLite a partir do código-fonte,
necessário para Android e iOS onde a biblioteca do sistema pode não estar
disponível. A configuração do Cargokit passa essa flag automaticamente em builds
de debug e release.</p>
<p><strong>App Flutter</strong> — Uma aplicação Material Design 3 com gerenciamento de estado
Riverpod, direcionada para Android, iOS, Linux, macOS e Windows a partir de uma
única base de código.</p>
<p>O <em>fluxo de onboarding</em> são três telas: uma tela de boas-vindas explicando o
projeto em uma frase ("Preserve suas memórias através dos milênios. Sem nuvem.
Sem empresa."), uma tela de criação de identidade que dispara a geração do par
de chaves Ed25519 em Rust, e uma tela de confirmação mostrando o nome do usuário
e a identidade criptográfica.</p>
<p>A <em>tela de timeline</em> exibe memórias em ordem cronológica reversa com previews de
imagem, texto de contexto e chips para tipo de memória e visibilidade.
Pull-to-refresh recarrega a partir do nó Rust. Um floating action button abre a
<em>tela de criação de memória</em>, que suporta seleção de foto da galeria ou câmera
via <code>image_picker</code>, texto de contexto opcional, dropdowns de tipo de memória e
visibilidade, e tags separadas por vírgula. Criar uma memória chama o FFI Rust
sincronamente, depois retorna à timeline.</p>
<p>A <em>tela de rede</em> mostra dois cards: status do nó (contagem de peers, tamanho da
DHT, estado de bootstrap, uptime) e saúde da replicação (total de fragmentos,
fragmentos saudáveis, fragmentos em reparo, fator de replicação). A <em>tela de
configurações</em> exibe a identidade do usuário — nome, node ID truncado, chave
pública truncada e data de criação.</p>
<p>Três providers Riverpod gerenciam o estado: <code>nodeProvider</code> inicia o nó embarcado
ao abrir o app usando o diretório de documentos e para ao fazer dispose;
<code>identityProvider</code> carrega o perfil existente ou cria um novo;
<code>timelineProvider</code> busca a lista de memórias com paginação.</p>
<p><strong>Testes</strong> — 9 testes unitários Rust em tesseras-embedded cobrindo ciclo de vida
do nó (start/stop sem panic), persistência de identidade entre reinícios, ciclos
de reinício sem corrupção do SQLite, streaming de eventos de rede, recuperação
de estatísticas, criação de memória e recuperação da timeline, e busca de
memória individual por hash. 2 testes Flutter: um teste de integração
verificando inicialização do Rust e startup do app, e um smoke test de widget.</p>
<h2 id="decisoes-de-arquitetura">Decisões de arquitetura</h2>
<ul>
<li><strong>Nó embarcado, não cliente-servidor</strong>: o celular roda a stack P2P completa,
não um thin client conversando com um daemon remoto. Isso significa que
memórias são preservadas mesmo sem internet. Usuários com um Raspberry Pi ou
VPS podem opcionalmente conectar o app ao seu daemon via GraphQL para maior
disponibilidade, mas não é obrigatório.</li>
<li><strong>FFI síncrono</strong>: todas as funções flutter_rust_bridge são marcadas como
<code>#[frb(sync)]</code> e bloqueiam no runtime Tokio interno. Isso simplifica o lado
Dart (sem complexidade de bridge assíncrono) enquanto o lado Rust lida com
concorrência internamente. A UI thread do Flutter permanece responsiva porque
o Riverpod envolve as chamadas em providers assíncronos.</li>
<li><strong>Singleton global</strong>: um global <code>Mutex&lt;Option&lt;EmbeddedNode&gt;&gt;</code> garante que o
ciclo de vida do nó seja previsível — um start, um stop, sem race conditions.
Plataformas mobile matam processos agressivamente, então simplicidade no
gerenciamento de ciclo de vida é uma feature.</li>
<li><strong>Tipos FFI planos</strong>: nenhuma abstração Rust vaza pela fronteira FFI. Todo
tipo é uma struct plana com strings e números. Isso torna os bindings Dart
auto-gerados confiáveis e fáceis de debugar.</li>
<li><strong>Onboarding de três telas</strong>: a criação de identidade é o único passo
obrigatório. Sem email, sem senha, sem registro em servidor. O app gera uma
identidade criptográfica localmente e está pronto para uso.</li>
</ul>
<h2 id="o-que-vem-a-seguir">O que vem a seguir</h2>
<ul>
<li><strong>Fase 4: Resiliência e Escala</strong> — NAT traversal avançado (STUN/TURN),
Shamir's Secret Sharing para herdeiros, tesseras seladas com criptografia
temporal, ajuste de performance, auditorias de segurança, empacotamento para
Alpine/Arch/Debian/FreeBSD/OpenBSD</li>
<li><strong>Fase 5: Exploração e Cultura</strong> — Navegador público de tesseras por
era/localização/tema/idioma, curadoria institucional, integração com
genealogia, exportação para mídia física (M-DISC, microfilme, papel livre de
ácido com QR)</li>
</ul>
<p>A infraestrutura está completa. A rede existe, a replicação funciona, e agora
qualquer pessoa com um celular pode participar. O que resta é fortalecer o que
temos e abrir para o mundo.</p>
</content>
</entry>
<entry xml:lang="pt-br">
<title>Reed-Solomon: Como o Tesseras Sobrevive à Perda de Dados</title>
<published>2026-02-14T14:00:00+00:00</published>
<updated>2026-02-14T14:00:00+00:00</updated>
<author>
<name>
Unknown
</name>
</author>
<link rel="alternate" type="text/html" href="https://tesseras.net/pt-br/news/reed-solomon/"/>
<id>https://tesseras.net/pt-br/news/reed-solomon/</id>
<content type="html" xml:base="https://tesseras.net/pt-br/news/reed-solomon/"><p>Seu disco rígido vai morrer. Seu provedor de nuvem vai pivotar. O array RAID no
seu armário vai sobreviver ao controlador, mas não ao dono. Se uma memória está
armazenada em exatamente um lugar, ela tem exatamente uma forma de se perder
para sempre.</p>
<p>Tesseras é uma rede que mantém memórias humanas vivas através de ajuda mútua. O
mecanismo central de sobrevivência é a <strong>codificação de apagamento
Reed-Solomon</strong> — uma técnica emprestada da comunicação espacial profunda que nos
permite reconstruir dados mesmo quando pedaços desaparecem.</p>
<h2 id="o-que-e-reed-solomon">O que é Reed-Solomon?</h2>
<p>Reed-Solomon é uma família de códigos corretores de erros inventada por Irving
Reed e Gustave Solomon em 1960. O caso de uso original era corrigir erros em
dados transmitidos por canais ruidosos — pense na Voyager enviando fotos de
Júpiter, ou num CD tocando apesar de arranhões.</p>
<p>A ideia-chave: se você adicionar redundância cuidadosamente calculada aos seus
dados <em>antes</em> que algo dê errado, você pode recuperar o original mesmo depois de
perder alguns pedaços.</p>
<p>Eis a intuição. Suponha que você tenha um polinômio de grau 2 — uma parábola.
Você precisa de 3 pontos para defini-lo de forma única. Mas se você avaliá-lo em
5 pontos, pode perder quaisquer 2 desses 5 e ainda reconstruir o polinômio a
partir dos 3 restantes. Reed-Solomon generaliza essa ideia para trabalhar sobre
corpos finitos (corpos de Galois), onde o "polinômio" são seus dados e os
"pontos de avaliação" são seus fragmentos.</p>
<p>Em termos concretos:</p>
<ol>
<li><strong>Divida</strong> seus dados em <em>k</em> shards de dados</li>
<li><strong>Calcule</strong> <em>m</em> shards de paridade a partir dos shards de dados</li>
<li><strong>Distribua</strong> todos os <em>k + m</em> shards em diferentes locais</li>
<li><strong>Reconstrua</strong> os dados originais a partir de quaisquer <em>k</em> dos <em>k + m</em>
shards</li>
</ol>
<p>Você pode perder até <em>m</em> shards — quaisquer <em>m</em>, de dados ou paridade, em
qualquer combinação — e ainda recuperar tudo.</p>
<h2 id="por-que-nao-simplesmente-fazer-copias">Por que não simplesmente fazer cópias?</h2>
<p>A abordagem ingênua para redundância é a replicação: faça 3 cópias, armazene-as
em 3 lugares. Isso dá tolerância a 2 falhas ao custo de 3x o seu armazenamento.</p>
<p>Reed-Solomon é dramaticamente mais eficiente:</p>
<table><thead><tr><th>Estratégia</th><th style="text-align: right">Overhead de armazenamento</th><th style="text-align: right">Falhas toleradas</th></tr></thead><tbody>
<tr><td>Replicação 3x</td><td style="text-align: right">200%</td><td style="text-align: right">2 de 3</td></tr>
<tr><td>Reed-Solomon (16,8)</td><td style="text-align: right">50%</td><td style="text-align: right">8 de 24</td></tr>
<tr><td>Reed-Solomon (48,24)</td><td style="text-align: right">50%</td><td style="text-align: right">24 de 72</td></tr>
</tbody></table>
<p>Com 16 shards de dados e 8 de paridade, você usa 50% de armazenamento extra mas
pode sobreviver à perda de um terço de todos os fragmentos. Para alcançar a
mesma tolerância a falhas só com replicação, você precisaria de 3x o
armazenamento.</p>
<p>Para uma rede que visa preservar memórias ao longo de décadas e séculos, essa
eficiência não é um luxo — é a diferença entre um sistema viável e um que se
afoga no próprio overhead.</p>
<h2 id="como-o-tesseras-usa-reed-solomon">Como o Tesseras usa Reed-Solomon</h2>
<p>Nem todos os dados merecem o mesmo tratamento. Uma memória de texto de 500 bytes
e um vídeo de 100 MB têm necessidades de redundância muito diferentes. O
Tesseras usa uma estratégia de fragmentação em três camadas:</p>
<p><strong>Small (&lt; 4 MB)</strong> — Replicação do arquivo inteiro para 7 pares. Para tesseras
pequenas, o overhead da codificação de apagamento (tempo de codificação,
gerenciamento de fragmentos, lógica de reconstrução) supera seus benefícios.
Cópias simples são mais rápidas e mais simples.</p>
<p><strong>Medium (4–256 MB)</strong> — 16 shards de dados + 8 de paridade = 24 fragmentos no
total. Cada fragmento tem aproximadamente 1/16 do tamanho original. Quaisquer 16
dos 24 fragmentos reconstroem o original. Distribuídos entre 7 pares.</p>
<p><strong>Large (≥ 256 MB)</strong> — 48 shards de dados + 24 de paridade = 72 fragmentos no
total. Maior contagem de shards significa fragmentos individuais menores (mais
fáceis de transferir e armazenar) e maior tolerância absoluta a falhas. Também
distribuídos entre 7 pares.</p>
<p>A implementação usa o crate <code>reed-solomon-erasure</code> operando sobre GF(2⁸) — o
mesmo corpo de Galois usado em códigos QR e CDs. Cada fragmento carrega um
checksum BLAKE3 para que a corrupção seja detectada imediatamente, não propagada
silenciosamente.</p>
<pre><code>Tessera (álbum de fotos de 120 MB)
↓ codificar
16 shards de dados (7,5 MB cada) + 8 shards de paridade (7,5 MB cada)
↓ distribuir
24 fragmentos entre 7 pares (diversidade de sub-rede)
↓ quaisquer 16 fragmentos
Tessera original recuperada
</code></pre>
<h2 id="os-desafios">Os desafios</h2>
<p>Reed-Solomon resolve o problema matemático da redundância. Os desafios de
engenharia estão em tudo ao redor.</p>
<h3 id="rastreamento-de-fragmentos">Rastreamento de fragmentos</h3>
<p>Cada fragmento precisa ser localizável. O Tesseras usa uma DHT Kademlia para
descoberta de pares e mapeamento de fragmentos para pares. Quando um nó fica
offline, seus fragmentos precisam ser recriados e distribuídos para novos pares.
Isso significa rastrear quais fragmentos existem, onde estão e se ainda estão
intactos — numa rede sem autoridade central.</p>
<h3 id="corrupcao-silenciosa">Corrupção silenciosa</h3>
<p>Um fragmento que retorna dados errados é pior que um ausente — pelo menos um
fragmento ausente é honestamente ausente. O Tesseras aborda isso com
verificações de saúde baseadas em atestação: o loop de reparo periodicamente
pede aos detentores de fragmentos que provem posse retornando checksums BLAKE3.
Se um checksum não bater, o fragmento é tratado como perdido.</p>
<h3 id="falhas-correlacionadas">Falhas correlacionadas</h3>
<p>Se todos os 24 fragmentos de uma tessera caírem em máquinas no mesmo datacenter,
uma única queda de energia os elimina todos. A matemática do Reed-Solomon assume
falhas independentes. O Tesseras impõe <strong>diversidade de sub-rede</strong> durante a
distribuição: no máximo 2 fragmentos por sub-rede /24 IPv4 (ou prefixo /48
IPv6). Isso espalha fragmentos por diferentes infraestruturas físicas.</p>
<h3 id="velocidade-de-reparo-vs-carga-na-rede">Velocidade de reparo vs. carga na rede</h3>
<p>Quando um par fica offline, o relógio começa a contar. Fragmentos perdidos
precisam ser recriados antes que mais falhas se acumulem. Mas reparo agressivo
inunda a rede. O Tesseras equilibra isso com um loop de reparo configurável
(padrão: a cada 24 horas com 2 horas de jitter) e limites de transferências
simultâneas (padrão: 4 transferências simultâneas). O jitter previne tempestades
de reparo onde cada nó verifica seus fragmentos no mesmo momento.</p>
<h3 id="gerenciamento-de-chaves-a-longo-prazo">Gerenciamento de chaves a longo prazo</h3>
<p>Reed-Solomon protege contra perda de dados, não contra perda de acesso. Se uma
tessera é criptografada (visibilidade privada ou selada), você precisa da chave
de descriptografia para tornar os dados recuperados úteis. O Tesseras separa
essas preocupações: codificação de apagamento cuida da disponibilidade, enquanto
o Compartilhamento de Segredo de Shamir (uma fase futura) cuidará da
distribuição de chaves entre herdeiros. A filosofia de design do projeto —
criptografar o mínimo possível — mantém o problema de gerenciamento de chaves
pequeno.</p>
<h3 id="limitacoes-do-corpo-de-galois">Limitações do corpo de Galois</h3>
<p>O corpo GF(2⁸) limita o número total de shards a 255 (dados + paridade
combinados). Para o Tesseras, isso não é uma restrição prática — mesmo a camada
Large usa apenas 72 shards. Mas significa que arquivos extremamente grandes com
milhares de fragmentos exigiriam um corpo diferente ou um esquema de codificação
em camadas.</p>
<h3 id="compatibilidade-evolutiva-do-codec">Compatibilidade evolutiva do codec</h3>
<p>Uma tessera codificada hoje precisa ser decodificável em 50 anos. Reed-Solomon
sobre GF(2⁸) é um dos algoritmos mais amplamente implementados na computação —
está em todo leitor de CD, em todo scanner de código QR, em toda sonda espacial.
Essa ubiquidade é em si uma estratégia de sobrevivência. O algoritmo não será
esquecido porque metade da infraestrutura do mundo depende dele.</p>
<h2 id="o-quadro-geral">O quadro geral</h2>
<p>Reed-Solomon é uma peça de um quebra-cabeça maior. Ele trabalha em conjunto com:</p>
<ul>
<li><strong>DHT Kademlia</strong> para encontrar pares e rotear fragmentos</li>
<li><strong>Checksums BLAKE3</strong> para verificação de integridade</li>
<li><strong>Reciprocidade bilateral</strong> para troca justa de armazenamento (sem blockchain)</li>
<li><strong>Diversidade de sub-rede</strong> para independência de falhas</li>
<li><strong>Reparo automático</strong> para manter a redundância ao longo do tempo</li>
</ul>
<p>Nenhuma técnica isolada faz memórias sobreviverem. Reed-Solomon garante que
dados <em>podem</em> ser recuperados. A DHT garante que fragmentos <em>podem ser
encontrados</em>. A reciprocidade garante que pares <em>querem ajudar</em>. O reparo
garante que nada disso se degrade com o tempo.</p>
<p>Uma tessera é uma aposta de que a soma desses mecanismos, rodando em muitas
máquinas independentes operadas por muitas pessoas independentes, é mais durável
que qualquer instituição isolada. Reed-Solomon é a fundação matemática dessa
aposta.</p>
</content>
</entry>
<entry xml:lang="pt-br">
<title>Fase 2: Memórias Sobrevivem</title>
<published>2026-02-14T12:00:00+00:00</published>
<updated>2026-02-14T12:00:00+00:00</updated>
<author>
<name>
Unknown
</name>
</author>
<link rel="alternate" type="text/html" href="https://tesseras.net/pt-br/news/phase2-replication/"/>
<id>https://tesseras.net/pt-br/news/phase2-replication/</id>
<content type="html" xml:base="https://tesseras.net/pt-br/news/phase2-replication/"><p>Uma tessera não está mais presa a uma única máquina. A Fase 2 entrega a camada
de replicação: os dados são divididos em fragmentos com codificação de
apagamento, distribuídos entre múltiplos pares e reparados automaticamente
quando nós ficam offline. Um livro-razão de reciprocidade bilateral garante
troca justa de armazenamento — sem blockchain, sem tokens.</p>
<h2 id="o-que-foi-construido">O que foi construído</h2>
<p><strong>tesseras-core</strong> (atualizado) — Novos tipos de domínio de replicação:
<code>FragmentPlan</code> (seleciona a camada de fragmentação baseada no tamanho da
tessera), <code>FragmentId</code> (hash da tessera + índice + contagem de shards +
checksum), <code>FragmentEnvelope</code> (fragmento com seus metadados para transporte na
rede), <code>FragmentationTier</code> (Small/Medium/Large), <code>Attestation</code> (prova de que um
nó possui um fragmento em um dado momento) e <code>ReplicateAck</code> (confirmação de
recebimento de fragmento). Três novas traits de porta definem os limites
hexagonais: <code>DhtPort</code> (encontrar pares, replicar fragmentos, solicitar
atestações, ping), <code>FragmentStore</code> (armazenar/ler/deletar/listar/verificar
fragmentos) e <code>ReciprocityLedger</code> (registrar trocas de armazenamento, consultar
saldos, encontrar melhores pares). O tamanho máximo de uma tessera é 1 GB.</p>
<p><strong>tesseras-crypto</strong> (atualizado) — O <code>ReedSolomonCoder</code> existente agora alimenta
a codificação de fragmentos. Os dados são divididos em shards, shards de
paridade são computados, e qualquer combinação de shards de dados pode
reconstruir o original — desde que o número de shards ausentes não exceda a
contagem de paridade.</p>
<p><strong>tesseras-storage</strong> (atualizado) — Dois novos adaptadores:</p>
<ul>
<li><code>FsFragmentStore</code> — armazena dados de fragmentos como arquivos em disco
(<code>{raiz}/{hash_tessera}/{indice:03}.shard</code>) com um índice de metadados SQLite
rastreando hash da tessera, índice do shard, contagem de shards, checksum e
tamanho em bytes. A verificação recalcula o hash BLAKE3 e compara com o
checksum armazenado.</li>
<li><code>SqliteReciprocityLedger</code> — contabilidade bilateral de armazenamento em
SQLite. Cada par tem uma linha rastreando bytes armazenados para eles e bytes
que eles armazenam para nós. A coluna <code>balance</code> é uma coluna gerada
(<code>bytes_they_store_for_us - bytes_stored_for_them</code>). UPSERT garante incremento
atômico dos contadores.</li>
</ul>
<p>Nova migração (<code>002_replication.sql</code>) adiciona tabelas para fragmentos, planos
de fragmentação, detentores, mapeamentos detentor-fragmento e saldos de
reciprocidade.</p>
<p><strong>tesseras-dht</strong> (atualizado) — Quatro novas variantes de mensagem: <code>Replicate</code>
(enviar um envelope de fragmento), <code>ReplicateAck</code> (confirmar recebimento),
<code>AttestRequest</code> (pedir a um nó que prove que possui os fragmentos de uma
tessera) e <code>AttestResponse</code> (retornar atestação com checksums e timestamp). O
engine trata essas mensagens em seu loop de despacho.</p>
<p><strong>tesseras-replication</strong> — O novo crate, com cinco módulos:</p>
<ul>
<li>
<p><em>Codificação de fragmentos</em> (<code>fragment.rs</code>): <code>encode_tessera()</code> seleciona a
camada de fragmentação baseada no tamanho e então chama a codificação
Reed-Solomon para as camadas Medium e Large. Três camadas:</p>
<ul>
<li><strong>Small</strong> (&lt; 4 MB): replicação do arquivo inteiro para r=7 pares, sem
codificação de apagamento</li>
<li><strong>Medium</strong> (4–256 MB): 16 shards de dados + 8 de paridade, distribuídos
entre r=7 pares</li>
<li><strong>Large</strong> (≥ 256 MB): 48 shards de dados + 24 de paridade, distribuídos
entre r=7 pares</li>
</ul>
</li>
<li>
<p><em>Distribuição</em> (<code>distributor.rs</code>): filtragem de diversidade de sub-rede limita
pares por sub-rede /24 IPv4 (ou prefixo /48 IPv6) para evitar falhas
correlacionadas. Se todos os seus fragmentos caírem no mesmo rack, uma única
queda de energia os elimina.</p>
</li>
<li>
<p><em>Serviço</em> (<code>service.rs</code>): <code>ReplicationService</code> é o orquestrador.
<code>replicate_tessera()</code> codifica os dados, encontra os pares mais próximos via
DHT, aplica diversidade de sub-rede e distribui fragmentos em round-robin.
<code>receive_fragment()</code> valida o checksum BLAKE3, verifica o saldo de
reciprocidade (rejeita se o déficit do remetente exceder o limite
configurado), armazena o fragmento e atualiza o livro-razão.
<code>handle_attestation_request()</code> lista os fragmentos locais e calcula seus
checksums como prova de posse.</p>
</li>
<li>
<p><em>Reparo</em> (<code>repair.rs</code>): <code>check_tessera_health()</code> solicita atestações dos
detentores conhecidos, recorre ao ping para nós não responsivos, verifica a
integridade local dos fragmentos e retorna uma de três ações: <code>Healthy</code>,
<code>NeedsReplication { deficit }</code> ou <code>CorruptLocal { fragment_index }</code>. O loop de
reparo roda a cada 24 horas (com 2 horas de jitter) via <code>tokio::select!</code> com
integração de desligamento.</p>
</li>
<li>
<p><em>Configuração</em> (<code>config.rs</code>): <code>ReplicationConfig</code> com padrões para intervalo
de reparo (24h), jitter (2h), transferências simultâneas (4), espaço livre
mínimo (1 GB), tolerância de déficit (256 MB) e limite de armazenamento por
par (1 GB).</p>
</li>
</ul>
<p><strong>tesd</strong> (atualizado) — O daemon agora abre um banco de dados SQLite
(<code>db/tesseras.db</code>), executa migrações, cria instâncias de <code>FsFragmentStore</code>,
<code>SqliteReciprocityLedger</code> e <code>FsBlobStore</code>, envolve o engine DHT em um
<code>DhtPortAdapter</code>, constrói um <code>ReplicationService</code> e lança o loop de reparo como
tarefa em segundo plano com desligamento gracioso.</p>
<p><strong>Testes</strong> — 193 testes em todo o workspace:</p>
<ul>
<li>15 testes unitários em tesseras-replication (camadas de codificação de
fragmentos, validação de checksum, diversidade de sub-rede, verificações de
saúde do reparo, fluxos de recebimento/replicação do serviço)</li>
<li>3 testes de integração com armazenamento real (ciclo completo
codificar→distribuir→receber para tessera média, replicação de arquivo inteiro
para tessera pequena, rejeição de fragmento adulterado)</li>
<li>Testes usam SQLite em memória + diretório temporário para fragmentos com mocks
mockall para DHT e BlobStore</li>
<li>Zero avisos do clippy, formatação limpa</li>
</ul>
<h2 id="decisoes-de-arquitetura">Decisões de arquitetura</h2>
<ul>
<li><strong>Fragmentação em três camadas</strong>: arquivos pequenos não precisam de
codificação de apagamento — o overhead não compensa. Arquivos médios e grandes
recebem progressivamente mais shards de paridade. Isso evita desperdiçar
armazenamento em tesseras pequenas enquanto oferece redundância forte para as
grandes.</li>
<li><strong>Distribuição por push do dono</strong>: o dono da tessera codifica os fragmentos e
os envia aos pares, em vez dos pares puxarem. Isso simplifica o protocolo (sem
fase de negociação) e garante que os fragmentos são distribuídos
imediatamente.</li>
<li><strong>Reciprocidade bilateral sem consenso</strong>: cada nó rastreia seu próprio saldo
com cada par localmente. Sem livro-razão global, sem token, sem blockchain. Se
o par A armazena 500 MB para o par B, o par B deveria armazenar
aproximadamente 500 MB para o par A. Free riders perdem redundância
gradualmente — seus fragmentos são despriorizados para reparo, mas nunca
deletados.</li>
<li><strong>Diversidade de sub-rede</strong>: os fragmentos são espalhados por diferentes
sub-redes para sobreviver a falhas correlacionadas. Uma queda de datacenter
não deveria eliminar todas as cópias de uma tessera.</li>
<li><strong>Verificações de saúde por atestação primeiro</strong>: o loop de reparo pede aos
detentores que provem posse (atestação com checksums) antes de declarar uma
tessera degradada. Apenas quando a atestação falha é que ele recorre a um
simples ping. Isso detecta corrupção silenciosa de dados, não apenas partida
de nós.</li>
</ul>
<h2 id="o-que-vem-a-seguir">O que vem a seguir</h2>
<ul>
<li><strong>Fase 3: API e Apps</strong> — App Flutter mobile/desktop via flutter_rust_bridge,
API GraphQL (async-graphql), nó WASM no navegador</li>
<li><strong>Fase 4: Resiliência e Escala</strong> — Assinaturas pós-quânticas ML-DSA, travessia
avançada de NAT, Compartilhamento de Segredo de Shamir para herdeiros,
empacotamento para Alpine/Arch/Debian/FreeBSD/OpenBSD, CI no SourceHut</li>
<li><strong>Fase 5: Exploração e Cultura</strong> — navegador público de tesseras, curadoria
institucional, integração genealógica, exportação para mídia física</li>
</ul>
<p>Os nós conseguem se encontrar e manter vivas as memórias uns dos outros. Em
seguida, damos às pessoas uma forma de segurar suas memórias nas mãos.</p>
</content>
</entry>
<entry xml:lang="pt-br">
<title>Fase 1: Nós Se Encontram</title>
<published>2026-02-14T11:00:00+00:00</published>
<updated>2026-02-14T11:00:00+00:00</updated>
<author>
<name>
Unknown
</name>
</author>
<link rel="alternate" type="text/html" href="https://tesseras.net/pt-br/news/phase1-basic-network/"/>
<id>https://tesseras.net/pt-br/news/phase1-basic-network/</id>
<content type="html" xml:base="https://tesseras.net/pt-br/news/phase1-basic-network/"><p>Tesseras não é mais uma ferramenta apenas local. A Fase 1 entrega a camada de
rede: nós se descobrem através de uma DHT Kademlia, comunicam-se sobre QUIC e
publicam ponteiros de tesseras que qualquer par na rede pode encontrar. Uma
tessera criada no nó A agora pode ser encontrada a partir do nó C.</p>
<h2 id="o-que-foi-construido">O que foi construído</h2>
<p><strong>tesseras-core</strong> (atualizado) — Novos tipos de domínio de rede:
<code>TesseraPointer</code> (referência leve aos detentores de uma tessera e localização
dos fragmentos), <code>NodeIdentity</code> (ID do nó + chave pública + nonce de prova de
trabalho), <code>NodeInfo</code> (identidade + endereço + capacidades) e <code>Capabilities</code>
(bitflags do que um nó suporta: DHT, armazenamento, relay, replicação).</p>
<p><strong>tesseras-net</strong> — A camada de transporte, construída sobre QUIC via quinn. A
trait <code>Transport</code> define a porta: <code>send</code>, <code>recv</code>, <code>disconnect</code>, <code>local_addr</code>.
Dois adaptadores a implementam:</p>
<ul>
<li><code>QuinnTransport</code> — QUIC real com TLS auto-assinado, negociação ALPN
(<code>tesseras/1</code>), pool de conexões via DashMap e um loop de aceitação em
background que trata streams recebidas.</li>
<li><code>MemTransport</code> + <code>SimNetwork</code> — canais em memória para testes determinísticos
sem I/O de rede. Cada teste de integração no crate DHT roda contra este
adaptador.</li>
</ul>
<p>O protocolo de fio usa MessagePack com prefixo de comprimento: um cabeçalho de 4
bytes big-endian seguido de um payload rmp-serde. <code>WireMessage</code> carrega um byte
de versão, ID de requisição e um corpo que pode ser requisição, resposta ou erro
de protocolo. Tamanho máximo de mensagem é 64 KiB.</p>
<p><strong>tesseras-dht</strong> — Uma implementação completa de Kademlia:</p>
<ul>
<li><em>Tabela de roteamento</em>: 160 k-buckets com k=20. Evicção do menos recentemente
visto, mover-para-trás ao atualizar, verificação por ping antes de substituir
a entrada mais antiga de um bucket cheio.</li>
<li><em>Distância XOR</em>: métrica XOR de 160 bits com indexação de bucket pelo bit mais
significativo diferente.</li>
<li><em>Prova de trabalho</em>: nós iteram um nonce até que
<code>BLAKE3(pubkey || nonce)[..20]</code> tenha 8 bits zero iniciais (~256 tentativas de
hash em média). Barato o suficiente para qualquer dispositivo, caro o
suficiente para tornar ataques Sybil impraticáveis em escala.</li>
<li><em>Mensagens de protocolo</em>: Ping/Pong, FindNode/FindNodeResponse,
FindValue/FindValueResult, Store — todos serializados com MessagePack via
serde.</li>
<li><em>Armazenamento de ponteiros</em>: armazenamento em memória limitado com TTL
configurável (24 horas padrão) e máximo de entradas (10.000 padrão). Quando
cheio, remove ponteiros mais distantes do ID do nó local, seguindo o modelo de
responsabilidade baseado em distância do Kademlia.</li>
<li><em>DhtEngine</em>: o orquestrador principal. Trata RPCs recebidos, executa buscas
iterativas (paralelismo alpha=3), bootstrap, publicação e busca. O método
<code>run()</code> dirige um loop <code>tokio::select!</code> com timers de manutenção: refresh da
tabela de roteamento a cada 60 segundos, expiração de ponteiros a cada 5
minutos.</li>
</ul>
<p><strong>tesd</strong> — Um binário de nó completo. Analisa argumentos de CLI (endereço de
bind, pares de bootstrap, diretório de dados), gera uma identidade de nó válida
por PoW, abre um endpoint QUIC, faz bootstrap na rede e roda o motor DHT.
Desligamento gracioso com Ctrl+C via tratamento de sinais do tokio.</p>
<p><strong>Infraestrutura</strong> — Configuração OpenTofu para dois nós bootstrap no Hetzner
Cloud (instâncias cx22 em Falkenstein, Alemanha e Helsinki, Finlândia). Script
de provisionamento cloud-init cria um usuário dedicado <code>tesseras</code>, escreve um
arquivo de configuração e configura um serviço systemd. Regras de firewall abrem
UDP 4433 (QUIC) e restringem métricas a acesso interno.</p>
<p><strong>Testes</strong> — 139 testes em todo o workspace:</p>
<ul>
<li>47 testes unitários em tesseras-dht (tabela de roteamento, distância, PoW,
armazenamento de ponteiros, serialização de mensagens, RPCs do engine)</li>
<li>5 testes de integração multi-nó (bootstrap de 3 nós, convergência de lookup
com 10 nós, publicar-e-encontrar, detecção de partida de nó, rejeição de PoW)</li>
<li>14 testes em tesseras-net (roundtrips de codec, send/recv de transporte,
backpressure, disconnect)</li>
<li>Testes de fumaça com Docker Compose usando 3 nós containerizados comunicando
sobre QUIC real</li>
<li>Zero avisos do clippy, formatação limpa</li>
</ul>
<h2 id="decisoes-de-arquitetura">Decisões de arquitetura</h2>
<ul>
<li><strong>Transport como porta</strong>: a trait <code>Transport</code> é a única interface entre o
motor DHT e a rede. Trocar QUIC por qualquer outro protocolo significa
implementar quatro métodos. Todos os testes de DHT usam o adaptador em
memória, tornando-os rápidos e determinísticos.</li>
<li><strong>Um stream por RPC</strong>: cada par requisição-resposta DHT usa um stream
bidirecional QUIC novo. Sem complexidade de multiplexação, sem bloqueio
head-of-line entre operações independentes. O QUIC trata a multiplexação no
nível da conexão.</li>
<li><strong>MessagePack em vez de Protobuf</strong>: codificação binária compacta sem geração
de código ou arquivos de esquema. Integração com serde significa que adicionar
um campo a uma mensagem é uma mudança de uma linha. Trade-off: sem garantias
de evolução de esquema embutidas, mas neste estágio velocidade importa mais.</li>
<li><strong>PoW em vez de stake ou reputação</strong>: uma identidade de nó custa ~256 hashes
BLAKE3. Isso roda em menos de um segundo em qualquer hardware, incluindo um
Raspberry Pi, mas gerar milhares de identidades para um ataque Sybil se torna
caro. Sem tokens, sem blockchain, sem dependências externas.</li>
<li><strong>Busca iterativa com atualização da tabela de roteamento</strong>: nós descobertos
são adicionados à tabela de roteamento conforme encontrados durante buscas
iterativas, seguindo o comportamento padrão do Kademlia. Isso garante que a
tabela de roteamento melhore organicamente conforme os nós interagem.</li>
</ul>
<h2 id="o-que-vem-a-seguir">O que vem a seguir</h2>
<ul>
<li><strong>Fase 2: Replicação</strong> — Codificação de apagamento Reed-Solomon pela rede,
distribuição de fragmentos, loops de reparo automáticos, livro-razão de
reciprocidade bilateral (sem blockchain, sem tokens)</li>
<li><strong>Fase 3: API e Apps</strong> — App Flutter mobile/desktop via flutter_rust_bridge,
API GraphQL (async-graphql), nó WASM no navegador</li>
<li><strong>Fase 4: Resiliência e Escala</strong> — Assinaturas pós-quânticas ML-DSA, travessia
avançada de NAT, Compartilhamento de Segredo de Shamir para herdeiros,
empacotamento para Alpine/Arch/Debian/FreeBSD/OpenBSD, CI no SourceHut</li>
<li><strong>Fase 5: Exploração e Cultura</strong> — navegador público de tesseras, curadoria
institucional, integração genealógica, exportação para mídia física</li>
</ul>
<p>Os nós conseguem se encontrar. Em seguida, aprendem a manter vivas as memórias
uns dos outros.</p>
</content>
</entry>
<entry xml:lang="pt-br">
<title>Fase 0: Fundação Construída</title>
<published>2026-02-14T10:00:00+00:00</published>
<updated>2026-02-14T10:00:00+00:00</updated>
<author>
<name>
Unknown
</name>
</author>
<link rel="alternate" type="text/html" href="https://tesseras.net/pt-br/news/phase0-foundation/"/>
<id>https://tesseras.net/pt-br/news/phase0-foundation/</id>
<content type="html" xml:base="https://tesseras.net/pt-br/news/phase0-foundation/"><p>O primeiro marco do projeto Tesseras está completo. A Fase 0 estabelece a
fundação sobre a qual cada componente futuro será construído: tipos de domínio,
criptografia, armazenamento e uma interface de linha de comando funcional.</p>
<h2 id="o-que-foi-construido">O que foi construído</h2>
<p><strong>tesseras-core</strong> — A camada de domínio define o formato tessera: <code>ContentHash</code>
(BLAKE3, 32 bytes), <code>NodeId</code> (Kademlia, 20 bytes), tipos de memória (Moment,
Reflection, Daily, Relation, Object), modos de visibilidade (Private, Circle,
Public, PublicAfterDeath, Sealed) e um formato de manifesto em texto plano que
pode ser interpretado por qualquer linguagem de programação pelos próximos mil
anos. A camada de serviço (<code>TesseraService</code>) gerencia operações de criação,
verificação, exportação e listagem através de port traits, seguindo arquitetura
hexagonal.</p>
<p><strong>tesseras-crypto</strong> — Geração de chaves Ed25519, assinatura e verificação. Um
framework de assinatura dual (Ed25519 + placeholder ML-DSA) pronto para migração
pós-quântica. Hashing de conteúdo com BLAKE3. Codificação de apagamento
Reed-Solomon atrás de uma feature flag para futura replicação.</p>
<p><strong>tesseras-storage</strong> — Índice SQLite via rusqlite com migrações em SQL puro.
Blob store no sistema de arquivos com layout endereçável por conteúdo
(<code>blobs/&lt;tessera_hash&gt;/&lt;memory_hash&gt;/&lt;filename&gt;</code>). Persistência de chaves de
identidade em disco.</p>
<p><strong>tesseras-cli</strong> — Um binário <code>tesseras</code> funcional com cinco comandos:</p>
<ul>
<li><code>init</code> — gera identidade Ed25519, cria banco de dados SQLite</li>
<li><code>create &lt;dir&gt;</code> — varre um diretório por arquivos de mídia, cria uma tessera
assinada</li>
<li><code>verify &lt;hash&gt;</code> — verifica assinatura e integridade dos arquivos</li>
<li><code>export &lt;hash&gt; &lt;dest&gt;</code> — escreve um diretório tessera autocontido</li>
<li><code>list</code> — mostra uma tabela das tesseras armazenadas</li>
</ul>
<p><strong>Testes</strong> — 67+ testes em todo o workspace: testes unitários em cada módulo,
testes baseados em propriedades (proptest) para roundtrips hex e serialização de
manifesto, testes de integração cobrindo o ciclo completo de
criação-verificação-exportação incluindo detecção de arquivos adulterados e
assinaturas inválidas. Zero avisos do clippy.</p>
<h2 id="decisoes-de-arquitetura">Decisões de arquitetura</h2>
<ul>
<li><strong>Arquitetura hexagonal</strong>: operações criptográficas são injetadas via trait
objects (<code>Box&lt;dyn Hasher&gt;</code>, <code>Box&lt;dyn ManifestSigner&gt;</code>,
<code>Box&lt;dyn ManifestVerifier&gt;</code>), mantendo o crate core livre de dependências
criptográficas concretas.</li>
<li><strong>Feature flags</strong>: a feature <code>service</code> no tesseras-core controla a camada de
aplicação assíncrona. As features <code>classical</code> e <code>erasure</code> no tesseras-crypto
controlam quais algoritmos são compilados.</li>
<li><strong>Manifesto em texto plano</strong>: interpretável sem qualquer biblioteca de formato
binário, com prefixos de hash explícitos <code>blake3:</code> e layout legível por
humanos.</li>
</ul>
<h2 id="o-que-vem-a-seguir">O que vem a seguir</h2>
<p>A Fase 0 é a fundação local. O caminho adiante:</p>
<ul>
<li><strong>Fase 1: Rede</strong> — Transporte QUIC (quinn), DHT Kademlia para descoberta de
pares, travessia de NAT</li>
<li><strong>Fase 2: Replicação</strong> — Codificação de apagamento Reed-Solomon pela rede,
loops de reparo, reciprocidade bilateral (sem blockchain, sem tokens)</li>
<li><strong>Fase 3: Clientes</strong> — App Flutter mobile/desktop via flutter_rust_bridge, API
GraphQL, nó WASM no navegador</li>
<li><strong>Fase 4: Endurecimento</strong> — Assinaturas pós-quânticas ML-DSA, empacotamento
para Alpine/Arch/Debian/FreeBSD/OpenBSD, CI no SourceHut</li>
</ul>
<p>O formato tessera é estável. Tudo construído a partir daqui se conecta e estende
o que existe hoje.</p>
</content>
</entry>
<entry xml:lang="pt-br">
<title>Olá, Mundo</title>
<published>2026-02-13T00:00:00+00:00</published>
<updated>2026-02-13T00:00:00+00:00</updated>
<author>
<name>
Unknown
</name>
</author>
<link rel="alternate" type="text/html" href="https://tesseras.net/pt-br/news/hello-world/"/>
<id>https://tesseras.net/pt-br/news/hello-world/</id>
<content type="html" xml:base="https://tesseras.net/pt-br/news/hello-world/"><p>Hoje anunciamos o projeto Tesseras: uma rede peer-to-peer para preservar
memórias humanas através dos milênios.</p>
<p>Tesseras é construído sobre uma ideia simples — suas fotos, gravações e escritos
merecem sobreviver a qualquer empresa, plataforma ou formato de arquivo. Cada
pessoa cria uma tessera, uma cápsula do tempo autocontida que a rede mantém viva
através de ajuda mútua e redundância.</p>
<p>O projeto está em seu estágio mais inicial. Estamos construindo a fundação:
ferramentas para criar, verificar e exportar tesseras offline. A camada de rede,
replicação e aplicativos virão em seguida.</p>
<p>Se essa missão ressoa com você,
<a href="/pt-br/subscriptions/">entre na lista de discussão</a> ou navegue pelo
<a rel="external" href="https://git.sr.ht/~ijanc/tesseras">código-fonte</a>.</p>
</content>
</entry>
</feed>
|